mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-12-04 04:17:53 +01:00
* when a constant Objective-C class reference is used for anything but
the methodpointer of a call, transform it into a call to the classclass
method because otherwise it can be used before the first call to any
method of the class (such as in the packages/cocoaint/src/IvarSize test)
and this can result in crashes
git-svn-id: trunk@18124 -
This commit is contained in:
parent
f9b27806e4
commit
20c3809c3a
@ -1877,6 +1877,11 @@ implementation
|
||||
firstpass would be called multiple times }
|
||||
include(callnodeflags,cnf_objc_processed);
|
||||
|
||||
{ make sure the methodpointer doesn't get translated into a call
|
||||
as well (endless loop) }
|
||||
if methodpointer.nodetype=loadvmtaddrn then
|
||||
tloadvmtaddrnode(methodpointer).forcall:=true;
|
||||
|
||||
{ A) set the appropriate objc_msgSend* variant to call }
|
||||
|
||||
{ record returned via implicit pointer }
|
||||
@ -1938,6 +1943,10 @@ implementation
|
||||
(selftree.resultdef.typ<>classrefdef) then
|
||||
begin
|
||||
selftree:=cloadvmtaddrnode.create(selftree);
|
||||
{ since we're in a class method of the current class, its
|
||||
information has already been initialized (and that of all of
|
||||
its parent classes too) }
|
||||
tloadvmtaddrnode(selftree).forcall:=true;
|
||||
typecheckpass(selftree);
|
||||
end;
|
||||
selfrestype:=selftree.resultdef;
|
||||
@ -1981,6 +1990,9 @@ implementation
|
||||
(methodpointer.resultdef.typ<>classrefdef)) then
|
||||
begin
|
||||
methodpointer:=cloadvmtaddrnode.create(methodpointer);
|
||||
{ no need to obtain the class ref by calling class(), sending
|
||||
this message will initialize it if necessary }
|
||||
tloadvmtaddrnode(methodpointer).forcall:=true;
|
||||
firstpass(methodpointer);
|
||||
end;
|
||||
end;
|
||||
@ -2013,7 +2025,10 @@ implementation
|
||||
vmttree:=methodpointer.getcopy;
|
||||
{ Only a typenode can be passed when it is called with <class of xx>.create }
|
||||
if vmttree.nodetype=typen then
|
||||
vmttree:=cloadvmtaddrnode.create(vmttree);
|
||||
begin
|
||||
vmttree:=cloadvmtaddrnode.create(vmttree);
|
||||
tloadvmtaddrnode(vmttree).forcall:=true;
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
|
||||
@ -31,9 +31,17 @@ interface
|
||||
|
||||
type
|
||||
tloadvmtaddrnode = class(tunarynode)
|
||||
{ unless this is for a call, we have to send the "class" message to
|
||||
the objctype because the type information only gets initialized
|
||||
after the first message has been sent -> crash if you pass an
|
||||
uninitialized type to e.g. class_getInstanceSize() or so. No need
|
||||
to save to/restore from ppu. }
|
||||
forcall: boolean;
|
||||
constructor create(l : tnode);virtual;
|
||||
function pass_1 : tnode;override;
|
||||
function pass_typecheck:tnode;override;
|
||||
function docompare(p: tnode): boolean; override;
|
||||
function dogetcopy: tnode; override;
|
||||
end;
|
||||
tloadvmtaddrnodeclass = class of tloadvmtaddrnode;
|
||||
|
||||
@ -190,6 +198,21 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function tloadvmtaddrnode.docompare(p: tnode): boolean;
|
||||
begin
|
||||
result:=inherited docompare(p);
|
||||
if result then
|
||||
result:=forcall=tloadvmtaddrnode(p).forcall;
|
||||
end;
|
||||
|
||||
|
||||
function tloadvmtaddrnode.dogetcopy: tnode;
|
||||
begin
|
||||
result:=inherited dogetcopy;
|
||||
tloadvmtaddrnode(result).forcall:=forcall;
|
||||
end;
|
||||
|
||||
|
||||
function tloadvmtaddrnode.pass_1 : tnode;
|
||||
var
|
||||
vs: tsym;
|
||||
@ -229,6 +252,19 @@ implementation
|
||||
else if (left.resultdef.typ=objectdef) then
|
||||
tobjectdef(left.resultdef).register_maybe_created_object_type
|
||||
end
|
||||
end
|
||||
else if is_objcclass(left.resultdef) and
|
||||
not(forcall) then
|
||||
begin
|
||||
{ call "class" method (= "classclass" in FPC), because otherwise
|
||||
we may use the class information before it has been
|
||||
initialized }
|
||||
vs:=search_struct_member(tobjectdef(left.resultdef),'CLASSCLASS');
|
||||
if not assigned(vs) or
|
||||
(vs.typ<>procsym) then
|
||||
internalerror(2011080601);
|
||||
{ can't reuse "self", because it will be freed when we return }
|
||||
result:=ccallnode.create(nil,tprocsym(vs),vs.owner,self.getcopy,[]);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user