When debugging gpc programs, I often get a gdb coredump when printing the value of string which is not -yet- initialized. This happens even more often when using ddd on top of gdb since the value is displayed as soon as you move the mouse pointer over the variable name.
This problem occurs because gdb uses the value of the 'length' field of the string type schema to print the string contents. If the string is not initialized, this field may contain any value -even negative- so it crashes gdb.
I solved this bug (IMHO this is one) by getting the Capacity field too. This field is always initialized for gpc strings - this is an assumption -. When printing a string, I compare the value of the actual length and the value of the capacity of the string. If the length is either negative or greater than the capacity, the capacity is used to print out the value. This modification has no impact on other Pascal string types (BP, etc).
I put the patches (4) for gdb 6.4 in attachment.
If someone estimates these patches are interesting enough to transmit them to the gdb maintainers, feel free to do so. I am not a member of the gdb mailing list and I do not know how to submit patches to them.
Hope this will help someone.
Kind regards
Pascal
Pascal Viandier wrote:
When debugging gpc programs, I often get a gdb coredump when printing the value of string which is not -yet- initialized. This happens even more often when using ddd on top of gdb since the value is displayed as soon as you move the mouse pointer over the variable name.
This problem occurs because gdb uses the value of the 'length' field of the string type schema to print the string contents. If the string is not initialized, this field may contain any value -even negative- so it crashes gdb.
I solved this bug (IMHO this is one) by getting the Capacity field too. This field is always initialized for gpc strings - this is an assumption -.
Yes (unless one does strange things), string capacity is initialized automatically. However, there may be a short time before the initialization code is executed (on program start, routine/block entry, or after the internal memory allocation in `New'), but when stepping on the source level, one might not encounter this (but I haven't checked).
When printing a string, I compare the value of the actual length and the value of the capacity of the string. If the length is either negative or greater than the capacity,
Negative length is, of course, always wrong, even if the capacity is unknown. In fact, you could also check if the capacity is <= 0 (then it's obviously not initialized). And if you have access to the (memory) size of the string (not sure -- I'm not familiar with gdb internals), you could check against "size - offset (characters)".
the capacity is used to print out the value.
Perhaps it would be better to print something like "uninitialized string", as the value is really invalid?
This modification has no impact on other Pascal string types (BP, etc).
I put the patches (4) for gdb 6.4 in attachment.
If someone estimates these patches are interesting enough to transmit them to the gdb maintainers, feel free to do so. I am not a member of the gdb mailing list and I do not know how to submit patches to them.
Me neither. I suppose Waldek could submit them, but since you're really the author, and the patch may be just a little too long to qualify as trivial under copyright law, you might have to sign a copyright assignment. I hope you won't mind.
Frank
-----Message d'origine-----
This problem occurs because gdb uses the value of the 'length' field of the string type schema to print the string contents. If the string is not initialized, this field may contain any value -even negative- so it crashes
gdb.
I solved this bug (IMHO this is one) by getting the Capacity field too. This field is always initialized for gpc strings - this is an assumption -.
Yes (unless one does strange things), string capacity is initialized automatically. However, there may be a short time before the initialization code is executed (on program start, routine/block entry, or after the internal memory allocation in `New'), but when stepping on the source level, one might not encounter this (but I haven't checked).
Among these strange things one can think of FillChar() if used improperly or Move() (As seen in a recent thread in this mailing list)
When printing a string, I compare the value of the actual length and the value of
the
capacity of the string. If the length is either negative or greater than the capacity,
Negative length is, of course, always wrong, even if the capacity is unknown. In fact, you could also check if the capacity is <= 0 (then it's obviously not initialized).
I did not test the value of the capacity field because of the assumption above but this is a good point.
And if you have access to the (memory) size of the string (not sure -- I'm not familiar with gdb internals), you could check against "size - offset (characters)".
This was my first choice but I did not find my way to get the size of the string so I solved this the other way.
the capacity is used to print out the value.
Perhaps it would be better to print something like "uninitialized string", as the value is really invalid?
I was not sure what to do. In fact, my first goal was to stop gdb from crashing each time I was moving the mouse over an uninitialized string variable name or a record containing one in ddd. OTOH, this kind of message could be misleading since it is the only Pascal type that would make it pop and I am not ready to implement this for all types ;-) - if it is feasible at all -. IMHO, showing the string contents is sufficient to see if the string was initialized since it is full of "random" characters if not.
This modification has no impact on other Pascal string types (BP, etc).
I put the patches (4) for gdb 6.4 in attachment.
If someone estimates these patches are interesting enough to transmit them
to
the gdb maintainers, feel free to do so. I am not a member of the gdb
mailing
list and I do not know how to submit patches to them.
Me neither. I suppose Waldek could submit them, but since you're really the author, and the patch may be just a little too long to qualify as trivial under copyright law, you might have to sign a copyright assignment. I hope you won't mind.
Pascal Viandier wrote:
I solved this bug (IMHO this is one) by getting the Capacity field too. This field is always initialized for gpc strings - this is an assumption -.
Yes (unless one does strange things), string capacity is initialized automatically. However, there may be a short time before the initialization code is executed (on program start, routine/block entry, or after the internal memory allocation in `New'), but when stepping on the source level, one might not encounter this (but I haven't checked).
Among these strange things one can think of FillChar() if used improperly or Move() (As seen in a recent thread in this mailing list)
Of course. As well as declaring strings in non-imported modules (a somewhat-FAQ), allocating strings with GetMem instead of New, wildly overwriting memory, etc.
the capacity is used to print out the value.
Perhaps it would be better to print something like "uninitialized string", as the value is really invalid?
I was not sure what to do. In fact, my first goal was to stop gdb from crashing each time I was moving the mouse over an uninitialized string variable name or a record containing one in ddd. OTOH, this kind of message could be misleading since it is the only Pascal type that would make it pop and I am not ready to implement this for all types ;-) - if it is feasible at all -.
For some types it's not possible (e.g., default integer types and Char allow all possible values). For some others, it would be possible (e.g., Boolean, most enum types, real (on most FP systems)), but IMHO one can do it one by one type when someone feels like doing it, it's not necessary to do for all types at once.
IMHO, showing the string contents is sufficient to see if the string was initialized since it is full of "random" characters if not.
But there's a difference between a string with invalid length (and possibly capacity), and a string with valid length and random contents.
Frank
<snip>
the capacity is used to print out the value.
Perhaps it would be better to print something like "uninitialized string", as the value is really invalid?
I was not sure what to do. In fact, my first goal was to stop gdb from
crashing
each time I was moving the mouse over an uninitialized string variable name
or a
record containing one in ddd. OTOH, this kind of message could be misleading since it is the only Pascal type that would make it pop and I am not ready
to
implement this for all types ;-) - if it is feasible at all -.
For some types it's not possible (e.g., default integer types and Char allow all possible values). For some others, it would be possible (e.g., Boolean, most enum types, real (on most FP systems)), but IMHO one can do it one by one type when someone feels like doing it, it's not necessary to do for all types at once.
IMHO, showing the string contents is sufficient to see if the string was initialized since it is full of "random" characters if not.
But there's a difference between a string with invalid length (and possibly capacity), and a string with valid length and random contents.
In this case, what do you think about the message "invalid data"? If the Capacity and/or length are invalid, the string content is probably invalid too - or at least it cannot be displayed nor handled properly by the running program -. This recalls me an old hairy bug: A program was systematically freezing when displaying data from an external source. It took many hours to discover what was happening: there was a "Control S" character (Chr(19)) embedded in the data. This was freezing the screen when displayed with WriteLn(). So it is probably not a so good idea to display invalid contents. It may contain control characters that could possibly disturb the controlling tty.
Your suggestion (Frank) to check the value of the Capacity is excellent. I will add the check (>= 0) in the patch.
Regards
Pascal
Pascal Viandier wrote:
In this case, what do you think about the message "invalid data"? If the Capacity and/or length are invalid, the string content is probably invalid too - or at least it cannot be displayed nor handled properly by the running program -.
Sounds good.
This recalls me an old hairy bug: A program was systematically freezing when displaying data from an external source. It took many hours to discover what was happening: there was a "Control S" character (Chr(19)) embedded in the data. This was freezing the screen when displayed with WriteLn(). So it is probably not a so good idea to display invalid contents. It may contain control characters that could possibly disturb the controlling tty.
Yes, such characters (which can also occur in valid strings) should be escaped, and there are sequences that do worse things than stopping the screen ...
But AFAICS, gdb already does that, even in (Borland) Pascal style -- though for input I use C notation:
(gdb) set language pascal (gdb) print "a\023b" $5 = 'a'#19'b'
Frank
Please find the revised gdb 6.4 patch to solve gdb coredump when printing uninitialized Pascal strings - in attachment - .
-----Message d'origine----- De : gpc-owner@gnu.de [mailto:gpc-owner@gnu.de] De la part de Frank Heckenbach Envoyé : April 4, 2006 15:21 À : gpc@gnu.de Objet : Re: RE : RE : An other gdb useful patch
Pascal Viandier wrote:
In this case, what do you think about the message "invalid data"? If the Capacity and/or length are invalid, the string content is probably invalid too - or at least it cannot be displayed nor handled properly by the running program -.
Sounds good.
So I did: the message is "<invalid data>". I added the "<" and ">" to make it look like the other messages in the same gdb module.
Kind regards
Pascal
At 9:54 -0400 4/4/06, Pascal Viandier wrote:
Your suggestion (Frank) to check the value of the Capacity is excellent. I will add the check (>= 0) in the patch.
Someone correct me if I'm wrong, but I believe the capacity for a string must be strictly greater than 0 to be valid.
s: String(0) is not valid, which is why you have to write code like:
procedure Doit( const t: String ); var s: String( Max(1,t.Length) ); begin ...
to make a string capable of holding string t with a runtime unknown length and capacity.
Enjoy, Peter.
Peter N Lewis wrote:
At 9:54 -0400 4/4/06, Pascal Viandier wrote:
Your suggestion (Frank) to check the value of the Capacity is excellent. I will add the check (>= 0) in the patch.
Someone correct me if I'm wrong, but I believe the capacity for a string must be strictly greater than 0 to be valid.
Right, Length >= 0, but Capacity > 0.
s: String(0) is not valid, which is why you have to write code like:
procedure Doit( const t: String ); var s: String( Max(1,t.Length) ); begin ...
to make a string capable of holding string t with a runtime unknown length and capacity.
Indeed.
Frank
-----Message d'origine----- De : gpc-owner@gnu.de [mailto:gpc-owner@gnu.de] De la part de Frank Heckenbach Envoyé : April 5, 2006 07:29 À : gpc@gnu.de Objet : Re: An other gdb useful patch
Peter N Lewis wrote:
At 9:54 -0400 4/4/06, Pascal Viandier wrote:
Your suggestion (Frank) to check the value of the Capacity is excellent. I will add the check (>= 0) in the patch.
Someone correct me if I'm wrong, but I believe the capacity for a string must be strictly greater than 0 to be valid.
Right, Length >= 0, but Capacity > 0.
So I did in the patch (Capacity > 0). It was a typo in my e-mail, not in the patch ;-)
Regards
Pascal