Delphi 10.3.1 编译器生成的代码在编译为 64 位时会发出异常

标签 delphi delphi-10.3-rio

仅当编译为 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/

相关文章:

delphi - 这是Rio上的System.Net.HttpClient中的错误吗?

android - arm-linux-androideabi-ld.exe 找不到-lrtlhelper

delphi - 遗留 Delphi 项目中的 32 位透明 PNG 问题

delphi - 如何更改控件内的鼠标光标?

delphi - TListView 记录按需加载

multithreading - 同步服务中的奇怪行为

delphi - 使用 RTTI 获取变量名称

delphi - ARC : is there a memory leak in TNetEncoding. 获取Base64Encoding?

delphi日期格式MM|dd|yy转MM/dd/yy错误