【发布时间】:2019-09-05 14:37:56
【问题描述】:
以下代码仅在编译为 64 位时才会在 Delphi 10.3.1 中生成异常 (c0000005 ACCESS_VIOLATION)。
但是,相同的代码在 Delphi 10.3.1 中编译为 32 位时不会产生异常。此外,在 Delphi 10.2.3 中编译为 32 位或 64 位时它不会失败。
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。如果我们将array of const更改为array of integer,64位代码仍然会失败,因此新的Delphi编译器似乎存在参数数量未知的数组问题。我们找到了通过为array of integer 创建类型来避免编译器错误的技巧,但这个技巧不适用于我们需要的array of const。
这是在 Delphi 10.3.1 中根据 CPU 视图为 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 位编译器错误还是我们遗漏了什么?有什么解决方法吗?
【问题讨论】:
-
这肯定是一个编译器错误。我认为您需要向 QualityPortal 提交报告。
-
还有一个不升级到 10.3.1 的理由,谢谢
-
@NasreddineGalfout,由于对高 DPI 支持的一些改进,我们进行了升级,第一印象总体上不错,但这个问题似乎是个大问题。
-
FWIW,东京代码也复制了数组,但该代码列在开始行下,而不是在继承下。东京使用正确的尺寸。 但这是 Rio 的一个错误,应该报告。
-
哦不,请不要另一个打开数组错误!不久前,我在 Delphi 5 中发现了一个讨厌的 codegen 错误,当在某些条件下使用开放数组时,它会破坏调用堆栈,并且该错误极大地影响了 Indy(它仍然支持 Delphi 5)并且是一个主要的 PITA 解决方案,到了“修复”如此丑陋的地步,我不想公开发布它。如果有 new 开放数组错误,我需要重新检查 Indy :-( Indy 中使用了相当多的开放数组。