以下代码仅在编译为64位时才在Delphi 10.3.1中生成异常(c0000005 ACCESS_VIOLATION)。
但是,当编译为32位时,同一代码在Delphi 10.3.1中不会生成异常。另外,在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位编译器错误,还是我们缺少任何内容?有解决方法吗?
答案 0 :(得分:14)
这是错误,应报告 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
答案 1 :(得分:1)
此错误的危害更广泛,它不处理程序/函数的VARed短字符串。
consider this SIMPLE code...
procedure Copyit(var s: shortstring); // VAR is important, pass by value ok
begin
debugform(s); // break point here
end;
procedure TForm1.Button1Click(Sender: TObject);
var
stuff: shortstring;
begin
stuff:= 'This is a demo string';
CopyIt(stuff);
end;
在32位模式下,它将生成您期望的代码。 在64位模式下,它生成的代码完全如上所述。 巨大的内存移动,rcx设置为$ 1FFFFFFFFFFFFFFFF !!!