Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2011-12

nostackframe -- possible to create faulty code?

5 messages · 2 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Bernd

Is it thoretically possible to make an otherwise perfectly working program crash with access violation only because I used the nostackframe modifier on a nested procedure?

I have observed this twice now, but I can't reliably reproduce it.

function TBoard.MoveGen(Index: Integer): Integer;
var
  Move: TMove;
  Index: Integer;
  [...] a lot more variables
  procedure AddMove; nostackframe;
  begin
    MoveBuffer[Index] := Move;     // MoveBuffer belongs to TBoard
    Inc(Index);
  end;

[...] // a lot more lines of complicated code and a few more nested procedures (but NO inline asm anywhere)

end;

If I declare the nested function inline then I haven't observed any problems (so far) and also with nostackframe sometimes it works but sometimes it will crash (depending on seemingly unrelated changes in other code) (I have not yet debugged where exactly It crashes, I'll do this the next time it happens).

But whatever it is: shouldn't this AddMove procedure here be perfectly allowed to be nostackframe because it has no own local variables and no arguments? Shouldn't it even be impossible to generate faulty code, by adding nostackframe even if it is not allowed for some reasons and rather get a compiler error or warning instead? (PS: *if* it works (if it does not crash) then it works correctly (finds all moves, no errors), so it seems there are no logical errors in the code and also activated range check etc. gives no errors).

Bernd

Jonas Maebe
to Bernd: Is it thoretically possible to make an otherwise perfectly working program crash with…
Bernd wrote
Is it thoretically possible to make an otherwise perfectly working program crash with access violation only because I used the nostackframe modifier on a nested procedure?

Yes. See also http://bugs.freepascal.org/bug_view_advanced_page.php?bug_id=15527

I think the "nostackframe" directive should probably only be allowed for pure assembler routines. In other cases it can only result in buggy code, since there is no way to know what the compiler will do.

Jonas

Bernd
to Bernd

2011/12/13 Bernd :

Show quoted text 10 lines
An unhandled exception occurred at $0806A90B : EAccessViolation : Access violation  $0806A90B  ADDMOVE,  line 61 of chess_movegen_inc.pas  $0806FAD2  TBOARD__PERFT,  line 33 of chess_search_inc.pas  $08066832  DOCOMMAND,  line 263 of chess_interface.pas  $08066D73  RUN,  line 359 of chess_interface.pas  $0804825D  main,  line 9 of fpwinglet.lpr Line 61 is:    MoveBuffer[Index] := Move;
  procedure AddMove; nostackframe;
  begin
    MoveBuffer[Index] := Move;

0x806a8e9 mov eax,DWORD PTR [ebp-0x4] <-- this is correct: eax := Index 0x806a8ec mov ecx,DWORD PTR [eax-0x8] <-- now what is this? makes no sense 0x806a8ef mov eax,DWORD PTR [ebp-0x4] <-- again? 0x806a8f2 mov eax,DWORD PTR [eax-0x4] <-- and again no sense? 0x806a8f5 imul eax,eax,0x14 <-- 0x14 would be SizeOf(TMove), correct.
0x806a8f8 mov edx,DWORD PTR [ebp-0x4] <-- edx := Index 0x806a8fb lea edi,[ecx+eax*1+0x50a8] <-- this cannot end well.... 0x806a902 lea esi,[edx-0x4c] <-- edx is not an address!!
0x806a905 cld
0x806a906 mov ecx,0x5
0x806a90b rep movs DWORD PTR es:[edi],DWORD PTR ds:[esi] <-- here the crach

    Inc(Index);

0x806a90d mov eax,DWORD PTR [ebp-0x4]
0x806a910 inc DWORD PTR [eax-0x4]