Компилятор Delphi 10.3.1 генерирует код, который выдает исключение при компиляции в 64 бита - PullRequest
10 голосов
/ 15 апреля 2019

Следующий код генерирует исключение (c0000005 ACCESS_VIOLATION) в Delphi 10.3.1 только при компиляции в 64-разрядную версию.

Однако этот же код не генерирует исключение в 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.Код по-прежнему не работает для 64 бит, если мы изменим array of const на array of integer, поэтому кажется, что у нового компилятора Delphi есть проблема с массивами с неизвестным числом параметров.Мы нашли способ избежать ошибки компилятора, создав тип для array of integer, но этот прием недоступен для того, что нам нужно array of const.

Это код ассемблера, сгенерированный для 64 битов в Delphi 10.3.1 в соответствии с CPU View :

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

И это код, сгенерированный для 64 бит в Delphi 10.2.3 для той же функции:

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

Это ошибка 64-битного компилятора в Delphi 10.3.1 или мы что-то упустили?Есть ли обходные пути?

1 Ответ

14 голосов
/ 15 апреля 2019

Это ошибка, о которой следует сообщить 1 . Как упомянуто в вопросе, это терпит неудачу для каждого типа открытого массива .

Обходной путь - определить массив как const в методе:

procedure Setup(const aParams: array of const); 

Объявляя открытый массив как const, передает массив по ссылке, в то время как без const он будет передаваться по значению как копия. В этом случае версия Rio дает сбой.


1 Сообщалось, что: Нарушение прав доступа при вызове унаследованной функции с параметром открытого массива в Rio

...