Who calls InvalidObjectError and why (other than the obvious!).
I searched the code but couldn't find any enlightening references as to who actually detects an invalid object and calls this...?
Thanks, Peter.
Peter N Lewis wrote:
Who calls InvalidObjectError and why (other than the obvious!).
I searched the code but couldn't find any enlightening references as to who actually detects an invalid object and calls this...?
AFAIK InvalidObjectError is only called when you give `-fobject-checking' option. In this case the compiler emits inline code to check that virtual method table looks sane (exists and does not correspond to an abstract object).
Waldek Hebisch wrote:
Peter N Lewis wrote:
Who calls InvalidObjectError and why (other than the obvious!).
I searched the code but couldn't find any enlightening references as to who actually detects an invalid object and calls this...?
BTW, it's called from compiler-generated code (not from RTS routines). The relevant line is in objects.c:
convert (TREE_TYPE (fun), build_predef_call (p_InvalidObjectError, NULL_TREE)), fun));
It is done before virtual method calls.
AFAIK InvalidObjectError is only called when you give `-fobject-checking' option. In this case the compiler emits inline code to check that virtual method table looks sane (exists and does not correspond to an abstract object).
Where "VMT exists" means that its VMT pointer is not nil, and in the structure it points to, the "NegatedSize" field contains the negative value of its "Size" field -- as a check against unintialized VMT pointers etc., not 100% foolproof, of course, and the same that BP does, BTW.
It doesn't actually check for abstract object types, but now that you mention it, I think it should. Though it's not easy to get an object with a VMT pointer to an abstract type (the compiler will normally prevent it), it is possible with some tricks (and of course, due to dangling pointers, memory corruption etc., which such runtime checks are meant to catch).
There are several ways to achieve it. One is to check for Size = 0. Since all object types in GPC have at least the VMT pointer, their size can never be 0, and GPC explicitly sets the Size field to 0 for abstract types. Another way is to produce an intentional mismatch of the NegatedSize field for abstract type VMTs. The following patch does the latter, as it avoids one more runtime check, and only changes the initialization of abstract VMTs.
Frank
I wrote:
It doesn't actually check for abstract object types, but now that you mention it, I think it should. Though it's not easy to get an object with a VMT pointer to an abstract type (the compiler will normally prevent it), it is possible with some tricks (and of course, due to dangling pointers, memory corruption etc., which such runtime checks are meant to catch).
There are several ways to achieve it.
(I.e., to achieve the checking, not producing the problem.)
One is to check for Size = 0. Since all object types in GPC have at least the VMT pointer, their size can never be 0, and GPC explicitly sets the Size field to 0 for abstract types. Another way is to produce an intentional mismatch of the NegatedSize field for abstract type VMTs. The following patch does the latter, as it avoids one more runtime check, and only changes the initialization of abstract VMTs.
PS: Necessary test program adjustment:
--- p/test/fjf636e.pas.orig Sat Jan 11 15:23:13 2003 +++ p/test/fjf636e.pas Thu Aug 3 21:02:10 2006 @@ -71,16 +71,16 @@ WriteLn ('failed 20 ', Name^, ' d') else with TypeOf (C)^ do if Size <> 0 then WriteLn ('failed 21 ', Size, ' ', 0) - else if NegatedSize <> 0 then - WriteLn ('failed 22 ', NegatedSize, ' ', 0) + else if NegatedSize <> -1 then + WriteLn ('failed 22 ', NegatedSize, ' ', -1) else if Parent <> nil then WriteLn ('failed 23 ', PtrInt (Parent), ' ', 0) else if Name^ <> 'C' then WriteLn ('failed 24 ', Name^, ' C') else with TypeOf (Ee)^ do if Size <> 0 then WriteLn ('failed 25 ', Size, ' ', 0) - else if NegatedSize <> 0 then - WriteLn ('failed 26 ', NegatedSize, ' ', 0) + else if NegatedSize <> -1 then + WriteLn ('failed 26 ', NegatedSize, ' ', -1) else if Parent <> nil then WriteLn ('failed 27 ', PtrInt (Parent), ' ', 0) else if Name^ <> 'Ee' then
Frank
Frank Heckenbach wrote:
I wrote:
It doesn't actually check for abstract object types, but now that you mention it, I think it should. Though it's not easy to get an object with a VMT pointer to an abstract type (the compiler will normally prevent it), it is possible with some tricks (and of course, due to dangling pointers, memory corruption etc., which such runtime checks are meant to catch).
There are several ways to achieve it.
(I.e., to achieve the checking, not producing the problem.)
One is to check for Size = 0. Since all object types in GPC have at least the VMT pointer, their size can never be 0, and GPC explicitly sets the Size field to 0 for abstract types. Another way is to produce an intentional mismatch of the NegatedSize field for abstract type VMTs. The following patch does the latter, as it avoids one more runtime check, and only changes the initialization of abstract VMTs.
PS: Necessary test program adjustment:
I have already (1 hour ago) applied the patch (thanks) and adjusted the test program.
BTW: Thanks for gpc.diff-volatile