[lazarus] Lazarus ansistring AV?

Marc Weustink marc at dommelstein.net
Fri Jul 25 17:52:12 EDT 2003


At 23:53 25-7-2003 +0200, Marco van de Voort wrote:
> > I am not sure, but maybe this is related.
> >
> > Since the beginning of July the listbox test program stopped
> > working. I didn't have time to investigate further.
>
>Neli and I debugged it a bit, and it seems to be an ansistring
>initialisation problem.
>
>Maybe it is, maybe not (only Neli had the AV, I didn't, he'll research it
>more deeply later), but the problem we did find was a problem anyway, so I'd
>like to warn for it.
>
>The problem is near win32callback.inc:148 (version 1.41)
>
>var LMessage : TLMessage;
>
>  With PLMInsertText(@LMessage)^ Do
>   Begin
>    [..]
>     Newtext:=string(lparam);
>    [..]
>   end;


Eeeekkk... seeing this, I can imagine the errors Micha described.
I don't know where it came from, but ppl, please be carefull. Don't mess 
with strings (and Interfaces and Dynamic arrays), they are dynamic and 
reference counted.
Please make in these cases the string still exsists.

Example:

function Good: String;
var
   S: String;
begin
   S := 'SomeText;  // The refcount of the sting becomes 1
   Result := S;     // The refcount of the sting becomes 2
end;               // S is cleared ->
                    // The refcount of the string becomes 1
                    // The string is still avaiable outside the function

function Bad: Integer;
var
   S: String;
begin
   S := 'SomeText;        // The refcount of the sting becomes 1
   Result := Integer(S);  // Strings are infact pointers, but this
                          // has no effect on the refcount
end;                     // S is cleared ->
                          // The refcount of the string becomes 0
                          // The string is cleared
                          // The result is useless

Once you start casting, you disable all nice compiler logic, and *you* have 
to make sure what you do.

>There are at least one, and possible _two_ bugs in this single line.
>
>First, because of the construct with the pointer and the @ in the WITH
>clause, newtext isn't initialised to zero (as ansistrings should)
>
>The declaration of LMessage should do that, but "TLMessage" doesn't contain
>the ansistring field, so it is not initialised to zero. When nextext is
>used, it is decreased in ref count, and since the random value points into
>deep space, so accessing the ref count via the pointer can produce an AV.
>
>It can be remedied by initing newtest to zero:
>
>integer(newtext):=0;            // pchar(newtext):=nil isn't allowed.

Why isnt the LMessage declared as TLMInsertText anyway ?

>The second problem is if you think what the assignment means:
>
>newtext:=string(lparam);
>
>With newtext=ansistring (which is a pointer type), and lparam is of type
>longint (or integer) it says:
>
>"type cast the integer value of lparam to a pointer. Store that pointer
>in the place "newtext"
>
>This while "lparam" is a pchar, IOW the pchar to ansistring conversion
>doesn't take place.
>
>So the correct typecast is:
>
>newtext:=pchar(lparam);
>
>Which says. "Lparam" is actually of type pchar, and assignment to an
>ansistring will trigger proper conversion.
>
>But in general I'd advise to keep such structures (as in lmessage etc)
>pchar only, to avoid both problems a bit.
>
>You can still assign the pchars to local "ansistring" variables.

But keep the lifetime of the string in mind. Cast a string to a PChar and 
post it as a message will never ever work and allways lead to the most 
unpredictable and hard to trace errors.

Marc (funny, today at work I had the same case)






More information about the Lazarus mailing list