仅当编译为 64 位时,以下代码才会在 Delphi 10.3.1 中生成异常 (c0000005 ACCESS_VIOLATION)。
但是,当编译为 32 位时,相同的代码在 Delphi 10.3.1 中不会生成异常。此外,当编译为 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.
问题似乎在于参数类型为 const 数组
。如果我们将const数组
更改为整型数组
,代码在64位上仍然会失败,因此看来新的Delphi编译器对未知数量的数组存在问题。参数。我们找到了通过创建整数数组
类型来避免编译器错误的技巧,但这个技巧不适用于我们需要的const数组
。
这是根据CPU View在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 位编译器错误还是我们遗漏了什么?有什么解决办法吗?
最佳答案
这是一个错误,应该报告1。正如问题中提到的,对于每种类型的开放数组,它都会失败。
解决方法是在方法中将数组定义为 const
:
procedure Setup(const aParams: array of const);
<小时/>
将开放数组声明为const
,通过引用传递数组,而如果没有const,它将作为副本按值传递。在这种情况下,Rio 版本会失败。
1 报告为:Access violation when calling an inherited function with an open array parameter in Rio
关于Delphi 10.3.1 编译器生成的代码在编译为 64 位时会发出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55692131/