delphi - Wrong code when combining anonymous and nested procedures -
i've got unexpected access violations delphi code think correct, seems miscompiled. can reduce to
procedure run(proc: tproc); begin proc; end; procedure test; begin run( procedure var s: pchar; procedure nested; begin run( procedure begin end); s := 'hello, world!'; end; begin run( procedure begin s := 'hello'; end); nested; showmessage(s); end); end;
what happens me s := 'hello, world!'
storing in wrong location. because of that, either access violation raised, or showmessage(s)
shows "hello" (and sometimes, access violation raised when freeing objects used implement anonymous procedures).
i'm using delphi xe, updates installed.
how can know going cause problems? know how rewrite code avoid anonymous procedures, have trouble figuring out in precisely situations lead wrong code, don't know avoid them.
it interesting me know if fixed in later versions of delphi, nothing more interesting, upgrading not option @ point.
on qc, recent report can find similar #91876, resolved in delphi xe.
update:
based on alexsc's comments, slight modification:
... procedure nested; begin run( procedure begin s := s; end); s := 'hello, world!'; end; ...
does work.
the generated machine code for
s := 'hello, world!';
in failing program is
scratchform.pas.44: s := 'hello, world!'; 004bd971 b89cd94b00 mov eax,$004bd99c 004bd976 894524 mov [ebp+$24],eax
whereas correct version is
scratchform.pas.45: s := 'hello, world!'; 004bd981 b8b0d94b00 mov eax,$004bd9b0 004bd986 8b5508 mov edx,[ebp+$08] 004bd989 8b52fc mov edx,[edx-$04] 004bd98c 89420c mov [edx+$0c],eax
the generated code in failing program not seeing s
has been moved compiler-generated class, [ebp+$24]
how outer local variables of nested methods accessed how local variables accessed.
without seeing whole assembler code whole (procedure test) , assuming on snippet posted, it's on failing snippet pointer has been moved on correct version there data moved too.
so seems s:=s or s:='' causes compiler create reference it's own , allocate memory, explain why works then.
i assume that's why access violation occurs without s:=s or s:='', because if there no memory allocated string (remember declared s: pchar) access violation raised because non-allocated memory accessed.
if declare s: string instead, won't happen.
additions after extended commenting:
a pchar pointer data structure, must exist. common issue pchar declare local variables , passing pchar variable other procs, because happens local variable freed once routine ends, pchar still point it, raise access violations once accessed.
the possibility exists per documentation declaring const s: pchar = 'hello, world!'
works because compiler can resolve relative adresse it. works constants , not variables on example above. doing in example above needs storage allocated string literal pchar points s:string; p:pchar; s:='hello, world!'; p:=pchar(s);
or similar.
if still fails declaring string or integer perhaps variable disappears somewhere along or isn't visible anymore in proc, issue has nothing existing pchar issue explained already.
final conclusion:
it's possible s:pchar; s:='hello, world!'
compiler allocates local or global constant const s: pchar = 'hello, world!'
saved executable, second s := 'hello'
creates 1 saved executable , on - s
points last 1 allocated, others still in executable not accessible more without knowing exact location, because s
points last 1 allocated.
so depending 1 last s
points either hello, world!
or hello
. on example above can guess 1 last , knows perhaps compiler can guess , depending on optimizations , other unpredictable factors s
point unallocated mem instead of last 1 time showmessage(s)
executed raises access violation.
Comments
Post a Comment