mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-12 12:26:02 +02:00
* Fixed exception handling in constructors of TP-style objects to correctly handle cases of statically allocated objects (must call destructor but do not free memory) and objects without destructor (must free memory if it was allocated dynamically).
+ Test extended. git-svn-id: trunk@26676 -
This commit is contained in:
parent
1b14ff7e8a
commit
a1dfaa54dd
@ -2226,11 +2226,14 @@ implementation
|
|||||||
if (cnf_new_call in callnodeflags) then
|
if (cnf_new_call in callnodeflags) then
|
||||||
vmttree:=cloadvmtaddrnode.create(ctypenode.create(methodpointer.resultdef))
|
vmttree:=cloadvmtaddrnode.create(ctypenode.create(methodpointer.resultdef))
|
||||||
else
|
else
|
||||||
{ destructor with extended syntax called from dispose
|
{ destructor with extended syntax called from dispose }
|
||||||
or destructor called from exception block in constructor }
|
{ value -1 is what fpc_help_constructor() changes VMT to when it allocates memory }
|
||||||
if (cnf_dispose_call in callnodeflags) or
|
if (cnf_dispose_call in callnodeflags) then
|
||||||
(cnf_create_failed in callnodeflags) then
|
vmttree:=cpointerconstnode.create(TConstPtrUInt(-1),voidpointertype)
|
||||||
vmttree:=cpointerconstnode.create(1,voidpointertype)
|
else
|
||||||
|
{ destructor called from exception block in constructor }
|
||||||
|
if (cnf_create_failed in callnodeflags) then
|
||||||
|
vmttree:=ctypeconvnode.create_internal(load_vmt_pointer_node,voidpointertype)
|
||||||
else
|
else
|
||||||
{ inherited call, no create/destroy }
|
{ inherited call, no create/destroy }
|
||||||
if (cnf_inherited in callnodeflags) then
|
if (cnf_inherited in callnodeflags) then
|
||||||
|
@ -758,19 +758,37 @@ implementation
|
|||||||
pd:=tobjectdef(procdef.struct).find_destructor;
|
pd:=tobjectdef(procdef.struct).find_destructor;
|
||||||
{ this will always be the case for classes, since tobject has
|
{ this will always be the case for classes, since tobject has
|
||||||
a destructor }
|
a destructor }
|
||||||
if assigned(pd) then
|
if assigned(pd) or is_object(procdef.struct) then
|
||||||
begin
|
begin
|
||||||
current_filepos:=exitpos;
|
current_filepos:=exitpos;
|
||||||
exceptblock:=internalstatements(newstatement);
|
exceptblock:=internalstatements(newstatement);
|
||||||
{ first free the instance if non-nil }
|
{ first free the instance if non-nil }
|
||||||
{ if vmt<>0 then call destructor }
|
if assigned(pd) then
|
||||||
addstatement(newstatement,cifnode.create(
|
{ if vmt<>0 then call destructor }
|
||||||
caddnode.create(unequaln,
|
addstatement(newstatement,
|
||||||
load_vmt_pointer_node,
|
cifnode.create(
|
||||||
cnilnode.create),
|
caddnode.create(unequaln,
|
||||||
{ cnf_create_failed -> don't call BeforeDestruction }
|
load_vmt_pointer_node,
|
||||||
ccallnode.create(nil,tprocsym(pd.procsym),pd.procsym.owner,load_self_node,[cnf_create_failed]),
|
cnilnode.create),
|
||||||
nil));
|
{ cnf_create_failed -> don't call BeforeDestruction }
|
||||||
|
ccallnode.create(nil,tprocsym(pd.procsym),pd.procsym.owner,load_self_node,[cnf_create_failed]),
|
||||||
|
nil))
|
||||||
|
else
|
||||||
|
{ object without destructor, call 'fail' helper }
|
||||||
|
addstatement(newstatement,
|
||||||
|
ccallnode.createintern('fpc_help_fail',
|
||||||
|
ccallparanode.create(
|
||||||
|
cordconstnode.create(tobjectdef(procdef.struct).vmt_offset,s32inttype,false),
|
||||||
|
ccallparanode.create(
|
||||||
|
ctypeconvnode.create_internal(
|
||||||
|
load_vmt_pointer_node,
|
||||||
|
voidpointertype),
|
||||||
|
ccallparanode.create(
|
||||||
|
ctypeconvnode.create_internal(
|
||||||
|
load_self_pointer_node,
|
||||||
|
voidpointertype),
|
||||||
|
nil))))
|
||||||
|
);
|
||||||
{ then re-raise the exception }
|
{ then re-raise the exception }
|
||||||
addstatement(newstatement,craisenode.create(nil,nil,nil));
|
addstatement(newstatement,craisenode.create(nil,nil,nil));
|
||||||
current_filepos:=entrypos;
|
current_filepos:=entrypos;
|
||||||
|
@ -782,7 +782,7 @@ procedure fpc_help_destructor(_self,_vmt:pointer;vmt_pos:cardinal);[public,alias
|
|||||||
begin
|
begin
|
||||||
{ already released? }
|
{ already released? }
|
||||||
if (_self=nil) or
|
if (_self=nil) or
|
||||||
(_vmt=nil) or
|
(_vmt<>pointer(-1)) or
|
||||||
(ppointer(_self+vmt_pos)^=nil) then
|
(ppointer(_self+vmt_pos)^=nil) then
|
||||||
exit;
|
exit;
|
||||||
if (pobjectvmt(ppointer(_self+vmt_pos)^)^.size=0) or
|
if (pobjectvmt(ppointer(_self+vmt_pos)^)^.size=0) or
|
||||||
|
@ -11,22 +11,62 @@ type
|
|||||||
destructor done; virtual;
|
destructor done; virtual;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
pobjnodestructor=^objnodestructor;
|
||||||
|
objnodestructor=object
|
||||||
|
constructor init;
|
||||||
|
end;
|
||||||
|
|
||||||
constructor obj.init;
|
constructor obj.init;
|
||||||
begin
|
begin
|
||||||
raise exception.create('oops!');
|
Abort;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor obj.done;
|
destructor obj.done;
|
||||||
begin
|
begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
constructor objnodestructor.init;
|
||||||
|
begin
|
||||||
|
Abort;
|
||||||
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
|
ps: obj;
|
||||||
|
ps2: objnodestructor;
|
||||||
p: pobj;
|
p: pobj;
|
||||||
|
p2: pobjnodestructor;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
HaltOnNotReleased:=true;
|
HaltOnNotReleased:=true;
|
||||||
|
{ Test 1: object with destructor, dynamically allocated. Must free memory. }
|
||||||
try
|
try
|
||||||
new(p,init);
|
new(p,init);
|
||||||
except
|
except
|
||||||
|
on EAbort do
|
||||||
|
else Halt(1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Test 2: object with destructor, statically allocated. Must not try to free memory. }
|
||||||
|
try
|
||||||
|
ps.init;
|
||||||
|
except
|
||||||
|
on EAbort do
|
||||||
|
else Halt(2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Test 3: object without destructor, dynamically allocated. }
|
||||||
|
try
|
||||||
|
new(p2,init);
|
||||||
|
except
|
||||||
|
on EAbort do
|
||||||
|
else Halt(3);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Test 4: object without desturtor, statically allocated. }
|
||||||
|
try
|
||||||
|
ps2.init;
|
||||||
|
except
|
||||||
|
on EAbort do
|
||||||
|
else Halt(4);
|
||||||
end;
|
end;
|
||||||
end.
|
end.
|
||||||
|
Loading…
Reference in New Issue
Block a user