【发布时间】:2015-12-08 09:30:10
【问题描述】:
我向您展示 Delphi 5 编译器中的一个错误。我知道不会有任何解决办法。但解决方法是 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.
真正的胆量是函数DoStuff,应该返回一个:
function DoStuff(): Integer;
var
foo: IFoo;
begin
foo := TFoo.Create;
try
Result := 1;
Exit;
finally
foo.Grob(0, 0);
end;
Result := 2;
end;
函数应该返回一个。相反,它返回接口对象的地址:
大会
代码实际上确实开始将结果设置为 1:
Project1.dpr.30:结果:= 1;
移动 ebx,$00000001 ;将返回值 1 放入 EBX
Project1.dpr.31:退出;
调用 @TryFinallyExit ;调用 finally 块
jmp DoStuff + $6E
当函数即将返回时,它确实将 EBX 复制到 EAX 中以便返回:
mov eax,ebx ;EBX 到 EAX 中返回但 finally 块(调用接口方法)是问题所在。它吹走了存储在 EBX 中的返回值:
我们从 调用@TryFinallyExit 到达这里 Project1.dpr.33: foo.Grob(0, 0); 异或 ecx,ecx 异或 edx,edx mov eax,[ebp-$04] mov ebx,[eax] 调用 dword ptr [ebx+$0c] ret“调用”到finally块后,返回跳转,跳转到:
Project1.dpr.36:结果:= 2;
...
xor eax,eax
流行音乐
流行音乐
流行音乐
mov fs:[eax],edx
推 $00442e1f
lea eax,[ebp-$04]
打电话给@IntfClear
ret
...
mov eax,ebx
流行音乐
流行音乐
流行音乐
ret
返回值不是一或二,而是接口指针的地址。
我知道你们都没有 Delphi 5。即使你有,
“你想让我说什么?”
我知道困难。我真正需要的是某种解决方法。
【问题讨论】:
-
我在这里看到的问题是,我们可以为这段代码提供一个解决方法,但它可能对真正的代码没有帮助........
-
我会尝试让“grob”不是虚拟的,看看它是否能解决问题。如果是这样,您总是可以将其称为虚拟“DoGrod”或类似的东西。
标签: delphi delphi-5 compiler-bug