[fpc-pascal] Weird FPC String Manager Bug

Tony Whyman tony.whyman at mccallumwhyman.com
Fri Mar 9 14:44:17 CET 2018


There seems to be some sort of weird race condition with the FPC 
string/memory manager. It is not easy to replicate, but the program 
Gabor Boros posted earlier today to the Lazarus list does seem to find 
the problem consistently.

The program he posted is a simple example of using MWA's Firebird Pascal 
Interface and causes an unhandled exception on program exit. This seems 
to occur after all user code has terminated and the heaptrc unit has 
reported its results. It only seems to occur when using "release" 
versions of the RTL and FCL libraries and not when using debug versions. 
A simple fix is to add "sleep(1);" to the end of the program. Just how 
weird it that!

I believe that I have isolated the problem to this code snippet - which 
looks simple enough:

procedure TOutputBlockItem.SetString(out S: AnsiString; Buf: PByte;
   Len: integer; CodePage: TSystemCodePage);
var rs: RawByteString;
begin
   system.SetString(rs,PAnsiChar(Buf),len);
   SetCodePage(rs,CodePage,false);
   S := rs;
end;

Its purpose is to set an AnsiString from text in a buffer and to set its 
codepage. If I change it to:

procedure TOutputBlockItem.SetString(out S: AnsiString; Buf: PByte;
   Len: integer; CodePage: TSystemCodePage);
var rs: RawByteString;
     i: integer;
begin
   rs := '';
   for i := 0 to len-1 do
     rs := rs + PAnsiChar(buf+i)^;
   SetCodePage(rs,CodePage,false);
   S := rs;
end;

then the bug goes away and the program completes normally. On the other 
hand, if I change it to:

procedure TOutputBlockItem.SetString(out S: AnsiString; Buf: PByte;
   Len: integer; CodePage: TSystemCodePage);
var rs: RawByteString;
begin
   SetLength(rs,len)
   if len > 0 then
     Move(Buf^,rs[1],len);
   SetCodePage(rs,CodePage,false);
   S := rs;
end;

then the exception is still raised at the end of the program. On the 
other hand, if I combine the two fixes to:

procedure TOutputBlockItem.SetString(out S: AnsiString; Buf: PByte;
   Len: integer; CodePage: TSystemCodePage);
var rs: RawByteString;
     i: integer;
begin
   SetLength(rs,len)
   if len > 0 then
     Move(Buf^,rs[1],len);
   rs := '';
   for i := 0 to len-1 do
     rs := rs + PAnsiChar(buf+i)^;
   SetCodePage(rs,CodePage,false);
   S := rs;
end;

then the program completes with no exception. My guess is that the 
problem is something to do with setting the length on a rawbytestring 
and its disposal when the rawbytestring goes out of scope. Can anyone 
see an obvious problem that I am missing?





More information about the fpc-pascal mailing list