Recent

Author Topic: Potential compiler bug with fpc_ansistr_decr_ref  (Read 1550 times)

Superdisk

  • Jr. Member
  • **
  • Posts: 54
Potential compiler bug with fpc_ansistr_decr_ref
« on: April 06, 2020, 07:44:48 am »
I wrote a function for reading null-terminated strings from a TStream.

Code: Pascal  [Select][+][-]
  1. function ReadNullTerm(S: TStream): String;
  2. var
  3.   B: Byte;
  4. label bleh;
  5. begin
  6.   Result := '';
  7.  
  8.   bleh:
  9.   B := S.ReadByte;
  10.   if B = 0 then Exit(Result);
  11.   Result += Char(B);
  12.   goto bleh
  13. end;

Inexplicably, at a certain point in the program when using this function, there's a SIGSEGV in fpc_ansistr_decr_ref.

I can call the function successfully some amount of times, and then it breaks later; pretty weird.

This happens in Lazarus 2.0.6. I tried with a later version from Trunk, and it seems like this bug is fixed, but:

  • I want to make sure it isn't just incidental that the bug isn't surfacing in Trunk
  • Am I actually doing something wrong?
  • What's the correct way to read a null terminated string from a TStream in 2.0.6 then?

I included the full program so you can easily reproduce the issue.

Thaddy

  • Hero Member
  • *****
  • Posts: 10271
Re: Potential compiler bug with fpc_ansistr_decr_ref
« Reply #1 on: April 06, 2020, 09:12:29 am »
I wrote a function for reading null-terminated strings from a TStream.
strlen ? It is in system, so defaults. (As are more C like PChar handling routines)

Also note #0 can be embedded in any true Pascal type string.

This is not a bug in any way.
https://www.freepascal.org/docs-html/rtl/classes/tstream.readansistring.html will work like you expect.
« Last Edit: April 06, 2020, 09:21:43 am by Thaddy »
I am more like donkey than shrek

PascalDragon

  • Hero Member
  • *****
  • Posts: 1922
  • Compiler Developer
Re: Potential compiler bug with fpc_ansistr_decr_ref
« Reply #2 on: April 06, 2020, 09:23:48 am »
  • I want to make sure it isn't just incidental that the bug isn't surfacing in Trunk
  • Am I actually doing something wrong?
  • What's the correct way to read a null terminated string from a TStream in 2.0.6 then?

Can you test whether you can reproduce the behaviour if you use a loop instead of a goto?

I wrote a function for reading null-terminated strings from a TStream.
strlen ? It is in system, so defaults. (As are more C like PChar handling routines)

Also note #0 can be embedded in any true Pascal type string.

This is not a bug in any way.

Thaddy, what nonsense is that again? How should Superdisk use strlen when they're reading from a TStream? They need to read byte by byte until they've found the NUL-character. And your comment regarding NUL is irrelevant in this case as well, cause Superdisk explicitly stated that they need to read a NUL-terminated string from a stream.

Also it might be a potential bug, because goto might upset the implicit exception handling.

Thaddy

  • Hero Member
  • *****
  • Posts: 10271
Re: Potential compiler bug with fpc_ansistr_decr_ref
« Reply #3 on: April 06, 2020, 09:27:53 am »
Well, The TStream.readansistring relies on what I explained, Sven. Look at its implementation. (Be a bit kind, I test this...and it is not nonsense)
« Last Edit: April 06, 2020, 09:29:28 am by Thaddy »
I am more like donkey than shrek

bytebites

  • Sr. Member
  • ****
  • Posts: 289
Re: Potential compiler bug with fpc_ansistr_decr_ref
« Reply #4 on: April 06, 2020, 09:33:00 am »
There is not length of the string in the example file, but ReadAnsiString expects it.

Thaddy

  • Hero Member
  • *****
  • Posts: 10271
Re: Potential compiler bug with fpc_ansistr_decr_ref
« Reply #5 on: April 06, 2020, 09:42:43 am »
Correct, it relies on a terminator.
I am more like donkey than shrek

bytebites

  • Sr. Member
  • ****
  • Posts: 289
Re: Potential compiler bug with fpc_ansistr_decr_ref
« Reply #6 on: April 06, 2020, 09:51:31 am »
Error occurs here, but disappears with -gh option:
Code: Pascal  [Select][+][-]
  1.  Result.Sections[I] := Default(TRSection);

lucamar

  • Hero Member
  • *****
  • Posts: 2958
Re: Potential compiler bug with fpc_ansistr_decr_ref
« Reply #7 on: April 06, 2020, 10:04:00 am »
What happens if you use this version?:

Code: Pascal  [Select][+][-]
  1. function ReadNullTerm(S: TStream): String;
  2. var
  3.   B: Byte;
  4. begin
  5.   Result := '';
  6.   repeat
  7.     B := S.ReadByte;
  8.     if B <> 0 then
  9.       Result := Result + Chr(B);
  10.   until (B = 0) or (S.Position >= S.Size);
  11. end;

The main difference (beyond the use of a loop and a stricter ending condition) is that instead of typecasting a byte to a char, as you do, this uses the corresponding conversion function Chr().

Note also that in your code this line:
Code: [Select]
  if B = 0 then Exit(Result);might produce unexpected results. Simply doing:
Code: [Select]
  if B = 0 then Exit;should be enough.
« Last Edit: April 06, 2020, 10:07:30 am by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.8/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Bart

  • Hero Member
  • *****
  • Posts: 3850
    • Bart en Mariska's Webstek
Re: Potential compiler bug with fpc_ansistr_decr_ref
« Reply #8 on: April 06, 2020, 12:50:01 pm »
Note also that in your code this line:
Code: [Select]
  if B = 0 then Exit(Result);might produce unexpected results. Simply doing:

While I agree that a simple Exit would suffice, I fail to see why Exit(Result) in this case can lead to unexpected results.
Could you elaborate on that?

Bart

BrunoK

  • Sr. Member
  • ****
  • Posts: 256
  • Retired programmer
Re: Potential compiler bug with fpc_ansistr_decr_ref
« Reply #9 on: April 06, 2020, 02:29:54 pm »
I downloaded you project. It compiles OK.

For me in debug mode, SIGSEGV is raised on second item (I=1) on line 98 of rgb2gbdk.lpr which is :
Code: Pascal  [Select][+][-]
  1.     Result.Sections[I] := Default(TRSection);
and not in ReadNullTerm.

WIN10 FPC 3.0.4  I386


Lazarus quite recent trunk (+/- changes regarding TScrollBar, IntitalSetupDialog, Options.Environment options).  FPC 3.0.4 (the mac os one) from svn + some mods.
Windows 10 Pro x64 (v. 1903 / 18362.418) and for test Linux Manjaro (QT5 and GTK2)


BrunoK

  • Sr. Member
  • ****
  • Posts: 256
  • Retired programmer
Re: Potential compiler bug with fpc_ansistr_decr_ref
« Reply #10 on: April 06, 2020, 02:50:23 pm »
Your bug is line 110:
Code: Pascal  [Select][+][-]
  1.         S.Read(Data, Size);
you overwrite the next records causing some side errror.
maybe you might try
Code: Pascal  [Select][+][-]
  1.         S.Read(Data[0], Size);
That one fails quickly (I=1) when Size = 0. So to go further, maybe modify to
Code: Pascal  [Select][+][-]
  1.         if Size<>0 then
  2.           S.Read(Data[0], Size);

Superdisk

  • Jr. Member
  • **
  • Posts: 54
Re: Potential compiler bug with fpc_ansistr_decr_ref
« Reply #11 on: April 06, 2020, 08:30:39 pm »
Thanks all for the info! BrunoK, looks like you're right, that's my mistake. I figured it would know what to do rather than just clobbering the pointer.  :(

Anyway, the fix of:

Code: Pascal  [Select][+][-]
  1. S.Read(Data[0], Size);

doesn't really seem like a good idea to me.. for one it triggers a range check error, and it seems like this is sort of a hack. What's the proper way to read into a dynamic array like this???

bytebites

  • Sr. Member
  • ****
  • Posts: 289
Re: Potential compiler bug with fpc_ansistr_decr_ref
« Reply #12 on: April 06, 2020, 09:40:06 pm »
Quote
triggers a range check error

Where and when?

Bart

  • Hero Member
  • *****
  • Posts: 3850
    • Bart en Mariska's Webstek
Re: Potential compiler bug with fpc_ansistr_decr_ref
« Reply #13 on: April 06, 2020, 10:51:54 pm »
Your code triggers a EAccessViolation at the moment it tries to access Result.Section[  1].
Code: Pascal  [Select][+][-]
  1. Result.Sections[I] := Default(TRSection);

The (adapted) ReadNullTerm() function doesn't seem to trigger any error.

At the start of ReadObjFile it finds the folowing values:
NumberOfSymbols=146
NumberOfSections=14

If you change S.Read(Data, Size) into S.Read(Data[0], Size) you get another AccesViolation later on, but this is because you then try do S.Read(Data[0], Size) where Size=0.

Channging that part to
Code: Pascal  [Select][+][-]
  1. ...
  2.       if ((SectType = ROMX) or (SectType = ROM0)) then begin
  3.         SetLength(Data, Size);
  4.         write('':3,' S.Read(Data,',Size,')');
  5.         if (Size>0) then BufSize:=S.Read(Data[0], Size) else BufSize:=0;
  6.         writeln(': OK (read: ',BufSize,')');
  7.         write('':3,' NumPatches=');
  8.         S.Read(NumPatches, SizeOf(NumPatches));
  9.         writeln(numpatches);
  10.         if NumPatches <> 0 then Die('Patches not supported');
  11. ...

Will then read sections till
Code: [Select]
Accessing Result.Section[  0]: OK
    Name=Note Table
    Size=144
    SectType=3
    Org=-1
    Bank=0
    Align=1
    S.Read(Data,144): OK (read: 144)
    NumPatches=0
Accessing Result.Section[  1]: OK
    Name=Wave stuff
    Size=0
    SectType=3
    Org=-1
    Bank=0
    Align=1
    S.Read(Data,0): OK (read: 0)
    NumPatches=0
Accessing Result.Section[  2]: OK
    Name=main
    Size=1626
    SectType=3
    Org=336
    Bank=0
    Align=1
    S.Read(Data,1626): OK (read: 1626)
    NumPatches=212
Patches not supported

I have no idea wether this output makes any sense to you.

Bart

jamie

  • Hero Member
  • *****
  • Posts: 3242
Re: Potential compiler bug with fpc_ansistr_decr_ref
« Reply #14 on: April 06, 2020, 11:30:21 pm »
I wrote a function for reading null-terminated strings from a TStream.

Code: Pascal  [Select][+][-]
  1. function ReadNullTerm(S: TStream): String;
  2. var
  3.   B: Byte;
  4. label bleh;
  5. begin
  6.   Result := '';
  7.  
  8.   bleh:
  9.   B := S.ReadByte;
  10.   if B = 0 then Exit(Result);
  11.   Result += Char(B);
  12.   goto bleh
  13. end;

Inexplicably, at a certain point in the program when using this function, there's a SIGSEGV in fpc_ansistr_decr_ref.

I can call the function successfully some amount of times, and then it breaks later; pretty weird.

This happens in Lazarus 2.0.6. I tried with a later version from Trunk, and it seems like this bug is fixed, but:

  • I want to make sure it isn't just incidental that the bug isn't surfacing in Trunk
  • Am I actually doing something wrong?
  • What's the correct way to read a null terminated string from a TStream in 2.0.6 then?

I included the full program so you can easily reproduce the issue.

 My version  :D
Code: Pascal  [Select][+][-]
  1. //-- My Verison of what I think the poster wants --
  2. function ReadNullTerm(S: TStream): String;
  3. var
  4.   B: Byte;
  5. begin
  6.   Result := '';
  7.   IF S.Position < S.Size then
  8.  Begin
  9.   B := S.ReadByte; //Read first one
  10.   While (B <> 0)and(S.Position < S.Size) do
  11.    Begin
  12.     Result := Result += Char(B); //Append it to string
  13.     B := S.ReadByte; // Read next one..
  14.    End;
  15.  end;
  16. end;
  17.  
  18.  
The only true wisdom is knowing you know nothing

 

TinyPortal © 2005-2018