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

时间:2019-04-15 15:07:04

标签: delphi delphi-10.3-rio

以下代码仅在编译为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位编译器错误,还是我们缺少任何内容?有解决方法吗?

2 个答案:

答案 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 !!!