Delphi 5 compiler bug returning interface pointer rather than return value
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.
As you observed, the compiler is storing the result into EBX
, but then overwriting it before it subsequently copies EBX
into EAX
to return the result to the caller.
The compiler should be doing one of the following:
EBX
does not destroy the result value, or EBX
in the call to Grob
, or Obviously options 1 and 2 are not readily available to you, but the latter is the workaround that you need to implement in this example – use a local variable to hold your intended Result
value until you are ready to return it:
function DoStuff(): Integer;
var
foo: IFoo;
MyResult: Integer;
begin
foo := TFoo.Create;
try
try
MyResult := 1;
Exit;
finally
foo.Grob(0, 0);
end;
MyResult := 2;
finally
Result := MyResult;
end;
end;
链接地址: http://www.djcxy.com/p/89892.html
上一篇: > ecx和edx寄存器中的内容歧义