* fixed bug that sporadically caused the column of certain nodes to

change, resulting in slightly different DWARF debug information
    (mantis #13508)

    The cause was saving a node pointer in a local variable, processing
    it further, and later on checking whether it changed by comparing
    the stored and the current instance pointer. The problem was that
    the node could have been freed and reallocated at the same address
    (but with different contents), so this check sometimes resulted
    in (hard to reproduce) false negatives.

git-svn-id: trunk@13580 -
This commit is contained in:
Jonas Maebe 2009-08-22 22:15:27 +00:00
parent 2f7457f37e
commit a64c5a7b23
2 changed files with 436 additions and 395 deletions

View File

@ -30,6 +30,7 @@ interface
procedure typecheckpass(var p : tnode);
function do_typecheckpass(var p : tnode) : boolean;
function do_typecheckpass_changed(var p : tnode; out nodechanged: boolean) : boolean;
procedure firstpass(var p : tnode);
function do_firstpass(var p : tnode) : boolean;
@ -57,7 +58,7 @@ implementation
Global procedures
*****************************************************************************}
procedure typecheckpass(var p : tnode);
procedure typecheckpass_internal(var p : tnode; out node_changed: boolean);
var
oldcodegenerror : boolean;
oldlocalswitches : tlocalswitches;
@ -65,6 +66,7 @@ implementation
oldpos : tfileposinfo;
hp : tnode;
begin
node_changed:=false;
if (p.resultdef=nil) then
begin
oldcodegenerror:=codegenerror;
@ -79,6 +81,7 @@ implementation
{ should the node be replaced? }
if assigned(hp) then
begin
node_changed:=true;
p.free;
{ run typecheckpass }
typecheckpass(hp);
@ -106,11 +109,27 @@ implementation
end;
function do_typecheckpass(var p : tnode) : boolean;
procedure typecheckpass(var p : tnode);
var
node_changed: boolean;
begin
typecheckpass_internal(p,node_changed);
end;
function do_typecheckpass_changed(var p : tnode; out nodechanged: boolean) : boolean;
begin
codegenerror:=false;
typecheckpass(p);
do_typecheckpass:=codegenerror;
typecheckpass_internal(p,nodechanged);
do_typecheckpass_changed:=codegenerror;
end;
function do_typecheckpass(var p : tnode) : boolean;
var
nodechanged: boolean;
begin
result:=do_typecheckpass_changed(p,nodechanged);
end;

View File

@ -1283,7 +1283,7 @@ implementation
Factor_read_id
---------------------------------------------}
procedure factor_read_id(var p1:tnode;var again:boolean);
procedure factor_read_id(out p1:tnode;var again:boolean);
var
pc : pchar;
srsym : tsym;
@ -1702,7 +1702,8 @@ implementation
PostFixOperators
---------------------------------------------}
procedure postfixoperators(var p1:tnode;var again:boolean);
{ returns whether or not p1 has been changed }
function postfixoperators(var p1:tnode;var again:boolean): boolean;
{ tries to avoid syntax errors after invalid qualifiers }
procedure recoverconsume_postfixops;
@ -1819,14 +1820,17 @@ implementation
{ shouldn't be used that often, so the extra overhead is ok to save
stack space }
dispatchstring : ansistring;
nodechanged : boolean;
label
skipreckklammercheck;
begin
result:=false;
again:=true;
while again do
begin
{ we need the resultdef }
do_typecheckpass(p1);
do_typecheckpass_changed(p1,nodechanged);
result:=result or nodechanged;
if codegenerror then
begin
@ -1887,6 +1891,7 @@ implementation
begin
consume(_LECKKLAMMER);
repeat
{ in all of the cases below, p1 is changed }
case p1.resultdef.typ of
pointerdef:
begin
@ -2152,6 +2157,11 @@ implementation
again:=false;
end;
end;
{ we only try again if p1 was changed }
if again or
(p1.nodetype=errorn) then
result:=true;
end; { while again }
end;
@ -2164,10 +2174,8 @@ implementation
l : longint;
ic : int64;
qc : qword;
oldp1,
p1 : tnode;
code : integer;
again : boolean;
srsym : tsym;
srsymtable : TSymtable;
pd : tprocdef;
@ -2177,8 +2185,13 @@ implementation
hs,hsorg : string;
hdef : tdef;
filepos : tfileposinfo;
again,
updatefpos,
nodechanged : boolean;
begin
oldp1:=nil;
{ can't keep a copy of p1 and compare pointers afterwards, because
p1 may be freed and reallocated in the same place! }
updatefpos:=false;
p1:=nil;
filepos:=current_tokenpos;
again:=false;
@ -2197,20 +2210,20 @@ implementation
else
factor_read_id(p1,again);
if again then
begin
if (p1<>oldp1) then
begin
if assigned(p1) then
begin
{ factor_read_id will set the filepos to after the id,
and in case of _SELF the filepos will already be the
same as filepos (so setting it again doesn't hurt). }
p1.fileinfo:=filepos;
oldp1:=p1;
filepos:=current_tokenpos;
end;
{ handle post fix operators }
postfixoperators(p1,again);
end;
updatefpos:=postfixoperators(p1,again);
end
else
begin
updatefpos:=true;
case token of
_RETURN :
begin
@ -2463,7 +2476,8 @@ implementation
begin
again:=true;
postfixoperators(p1,again);
end;
end
else
consume(_RKLAMMER);
end
else
@ -2475,6 +2489,7 @@ implementation
end;
got_addrn:=false;
p1:=caddrnode.create(p1);
p1.fileinfo:=filepos;
if cs_typed_addresses in current_settings.localswitches then
include(p1.flags,nf_typedaddr);
{ Store the procvar that we are expecting, the
@ -2590,6 +2605,7 @@ implementation
consume(token);
end;
end;
end;
{ generate error node if no node is created }
if not assigned(p1) then
@ -2598,14 +2614,18 @@ implementation
Comment(V_Warning,'factor: p1=nil');
{$endif}
p1:=cerrornode.create;
updatefpos:=true;
end;
{ get the resultdef for the node }
if (not assigned(p1.resultdef)) then
do_typecheckpass(p1);
begin
do_typecheckpass_changed(p1,nodechanged);
updatefpos:=updatefpos or nodechanged;
end;
if assigned(p1) and
(p1<>oldp1) then
updatefpos then
p1.fileinfo:=filepos;
factor:=p1;
end;
@ -2736,9 +2756,9 @@ implementation
var
p1,p2 : tnode;
oldafterassignment : boolean;
oldp1 : tnode;
filepos : tfileposinfo;
oldafterassignment,
updatefpos : boolean;
begin
oldafterassignment:=afterassignment;
@ -2749,7 +2769,7 @@ implementation
filepos:=current_tokenpos;
if token in [_ASSIGNMENT,_PLUSASN,_MINUSASN,_STARASN,_SLASHASN] then
afterassignment:=true;
oldp1:=p1;
updatefpos:=true;
case token of
_POINTPOINT :
begin
@ -2792,12 +2812,14 @@ implementation
p2:=sub_expr(opcompare,true);
p1:=gen_c_style_operator(slashn,p1,p2);
end;
else
updatefpos:=false;
end;
{ get the resultdef for this expression }
if not assigned(p1.resultdef) then
do_typecheckpass(p1);
afterassignment:=oldafterassignment;
if p1<>oldp1 then
if updatefpos then
p1.fileinfo:=filepos;
expr:=p1;
end;