以下代码仅在编译为 64 位时才会在 Delphi 10.3.1 中生成异常 (c0000005 ACCESS_VIOLATION)。
但是,相同的代码在 Delphi 10.3.1 中编译为 32 位时不会产生异常。此外,当编译为 32 位或 64 位时,它在 Delphi 10.2.3 中也不会失败。
program CrashOn64;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
TMyBaseClass = class
protected
procedure Setup(aParams: array of const); virtual;
public
end;
type
TMyWorkClass = class(TMyBaseClass)
protected
procedure DoSetup; virtual;
public
procedure Setup(aParams: array of const); override;
end;
{ TMyBaseClass }
procedure TMyBaseClass.Setup(aParams: array of const);
begin
end;
{ TMyWorkClass }
procedure TMyWorkClass.DoSetup;
begin
inherited;
end;
procedure TMyWorkClass.Setup(aParams: array of const);
begin
inherited;
DoSetup
end;
// main
var
myClass: TMyWorkClass;
begin
try
myClass:=TMyWorkClass.Create;
try
myClass.Setup([123]); // <-- Crash on Windows 64-bit
writeln('OK!')
finally
myClass.Free
end
except
on E: Exception do Writeln(E.ClassName, ': ', E.Message);
end;
readln; // Wait for Enter key
end.
问题似乎在于参数类型是array of const
. 如果我们更改为 64 位,代码仍然会失败array of const
,array of integer
因此新的 Delphi 编译器似乎存在参数数量未知的数组的问题。我们找到了通过创建一个类型来避免编译器错误的技巧,array of integer
但是这个技巧对于我们需要的东西是不可用的array of const
。
这是根据CPU 视图在 Delphi 10.3.1 中为 64 位生成的汇编代码:
CrashOn64.dpr.41: inherited;
0000000000428888 488B7528 mov rsi,[rbp+$28]
000000000042888C 488D7D20 lea rdi,[rbp+$20]
0000000000428890 48B9FFFFFFFFFFFFFF1F mov rcx,$1fffffffffffffff <<< What????????
000000000042889A F348A5 rep movsq <<< Crashes here.
000000000042889D A5 movsd
000000000042889E 66A5 movsw
00000000004288A0 A4 movsb
00000000004288A1 488B4D50 mov rcx,[rbp+$50]
00000000004288A5 488D5520 lea rdx,[rbp+$20]
00000000004288A9 448B4560 mov r8d,[rbp+$60]
00000000004288AD E8CEFEFFFF call TMyBaseClass.Setup
这是在 Delphi 10.2.3 中为相同功能生成的 64 位代码:
CrashOn64.dpr.41: inherited;
0000000000427329 488B4D50 mov rcx,[rbp+$50]
000000000042732D 488B5528 mov rdx,[rbp+$28]
0000000000427331 448B4560 mov r8d,[rbp+$60]
0000000000427335 E8E6FEFFFF call TMyBaseClass.Setup
这是 Delphi 10.3.1 中的 64 位编译器错误还是我们遗漏了什么?有什么解决方法吗?