Hi,
Rather than dumping all this information into a bug report I decided to write an email.
Here's a test program (attached) and a discussion of what goes wrong. Thanks again to Marco for explaining this to me and walking me through.
For the line
__globi := TTest.Create;a few things are generated:
a) a call to TTest.Create
b) a call to fpc_intf_assign, which in turn calls TTest._AddRef
the call to Create is fine, nothing wrong with it. However, the call to _AddRef goes wrong.
Now, heres what this actually looks like:
This is the call to Create and to intf_assign is fine: call SYSTEM_TOBJECT_$__CREATE
testl %eax,%eax
je .L16
addl $44,%eax
.L16:
pushl %eax
pushl $U_P$TESTII___GLOBI
call fpc_intf_assign
fpc_intf_assign calls AddRef from the VMT, which points to this code:
WRPR_P$TESTII_TTEST_$_ITESTINT_$_2_$_SYSTEM_TINTERFACEDOBJECT_$___ADDREF: subl $44,(%esp)
jmp SYSTEM_TINTERFACEDOBJECT_$___ADDREF
Marco explained to me that this looks like tailcall optimization, however for one this doesn't even make sense here (because fpc_intf_assign has to do something else [check the destination and _release on it] after _addref); however this is the reason why the program bombs out.
The call %eax in fpc_intf_assign pushes the correct return address within fpc_intf_assign onto the stack. Now, above code decrements it by 44 (0x2C). The new return address is now the following instruction from fpc_intf_incr_ref:
mov (%eax), %eax
Which segfaults immediately because %eax contains the return value of _addref (stdcall calling convention) which is 1 in this case.
I don't really know where the problem is (ie, why the compiler generates this code), however this keeps reference counted interfaces from working at all.
johannes
