Hi all, It seems like that when you call a method of an interface, a 'hidden' wrapper is generated by the compiler to adjust the 'self' parameter so that it does not refers to the interface-pointer, but the actual class-pointer.
The problem is only that the extra 'call' which is made adds one extra value to the stack, so that the parameters which are passed on the stack are all shifted. This is especially troublesome when the method is defined as cdecl and the 'self' parameter itself is also passed using the stack. (self is not on the location EBP+8 anymore, but EBP+12) See the attached example. It will crash when 'self' is referenced within the call to the method though an interface. I don't know what's the best way to fix this. I see three solutions: 1: replace the 'call' in the wrapper with a 'jmp'. I've tried this and it works, but when the function returns, the 'self'-class-pointer is not converted to the interface-pointer. But I don't see why this is done in the first place?!? Other problem is that you get a somewhat strange function-name in your stacktrace. (the name of the wrapper) 2: See if we can let the caller do the interface-pointer-to-class-pointer conversion. That way the wrapper is not necessary anymore. Leads to somewhat faster code, though less compact. But this is only possible if the caller has enough information to do the conversion. I'm not sure if that's the case. 3: Use some tricks in the wrapper to shift the stack-frame. But I don't see a proper (thread-friendly) way to do this. 4: Make the hidden wrapper a real wrapper and let it push all parameters on the stack again in the proper order. This generates a lot of overhead, offcourse. I would say that 2 is the best option, but I'm not sure if it is possible at all. So maybe that option 1 is a good idea? Joost. --
program testcdeclintf; {$mode objfpc}{$H+} type IJoostIntf = interface ['{3C409C8B-3A15-44B2-B22D-6BAA2071CAAD}'] function DoSomething : longint; cdecl; end; { TJoostClass } TJoostClass = class(TInterfacedObject,IJoostIntf) private FCounter: integer; public function DoSomething : longint; cdecl; end; { TJoostClass } function TJoostClass.DoSomething: longint; cdecl; begin inc(FCounter); // segfault here when self is invalid result := FCounter; end; var js: TJoostClass; ji: IJoostIntf; i: longint; begin js := TJoostClass.Create; i := js.DoSomething; // js.getinterface(IJoostIntf,ji); ji := IJoostIntf(js); i := ji.DoSomething; // Here self isn't passed correctly if i <> 2 then halt(1); writeln('ok'); end.
_______________________________________________ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel