I present you a bug in the Delphi 5 compiler. I know there's not going to be any fix for it; but a workaround would be super
program Project1;
uses
Dialogs, SysUtils;
{$R *.RES}
type
IFoo = interface
['{D68DA49A-F870-433D-9343-4964BFECFF27}']
procedure Grob(a: Integer; b: Integer);
end;
TFoo = class(TInterfacedObject, IFoo)
public
procedure Grob(a: Integer; b: Integer); virtual;
end;
procedure TFoo.Grob(a: Integer; b: Integer);
begin
end;
function DoStuff(): Integer;
var
foo: IFoo;
begin
foo := TFoo.Create;
try
Result := 1;
Exit;
finally
foo.Grob(0, 0);
end;
Result := 2;
end;
var
n: Integer;
begin
n := DoStuff;
if n <> 0 then
ShowMessage('Failed: '+IntToStr(n))
else
ShowMessage('Passed: '+IntToStr(n));
end.
The real guts is the function DoStuff which should return one:
function DoStuff(): Integer;
var
foo: IFoo;
begin
foo := TFoo.Create;
try
Result := 1;
Exit;
finally
foo.Grob(0, 0);
end;
Result := 2;
end;
The function should return one. Instead it returns the address of the interfaced object:
The assembly
The code actually does start to set the result to one:
Project1.dpr.30: Result := 1;
mov ebx,$00000001 ; place return value 1 in EBX
Project1.dpr.31: Exit;
call @TryFinallyExit ; call the finally block
jmp DoStuff + $6E
and as the function is about to return, it does copy EBX into EAX in order to return it:
mov eax,ebx ;EBX into EAX for return
But finally block (calling the interfaced method) is the problem. It blows away the return value stored in EBX:
We arrive here from the call @TryFinallyExit
Project1.dpr.33: foo.Grob(0, 0);
xor ecx,ecx
xor edx,edx
mov eax,[ebp-$04]
mov ebx,[eax] <----- overwriting ebx with interface address
call dword ptr [ebx+$0c]
ret
After the "call" to the finally block, it returns to a jump, which sends it to:
Project1.dpr.36: Result := 2;
...
xor eax,eax
pop edx
pop ecx
pop ecx
mov fs:[eax],edx
push $00442e1f
lea eax,[ebp-$04]
call @IntfClear
ret
...
mov eax,ebx <----- places overwritten EBX into EAX for return
Project1.dpr.37: end;
pop ebx
pop ecx
pop ebp
ret
The return value rather than being one, or two, is the address of the interface pointer.
I know none of you have Delphi 5. And even if you did,
"What would you like me to say?"
I know the difficulty. What i actually need is some sort of workaround.
