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

Следующий код создает исключение (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 или мы что-то упустили? Есть ли обходные пути?


person Pep    schedule 15.04.2019    source источник
comment
Наверняка это ошибка компилятора. Думаю, вам нужно отправить отчет в QualityPortal.   -  person David Heffernan    schedule 15.04.2019
comment
Еще одна причина не обновляться до 10.3.1, спасибо   -  person Nasreddine Galfout    schedule 15.04.2019
comment
@NasreddineGalfout, мы обновились из-за некоторых улучшений в поддержке высокого разрешения, и первые впечатления в целом были хорошими, но эта проблема, похоже, не работает.   -  person Pep    schedule 15.04.2019
comment
Должна быть возможность обойти это. Например, рассмотрим типизированную константу Integer. Это работает?   -  person David Heffernan    schedule 15.04.2019
comment
array of const фактически array of TVarRec - возможно, что-то изменилось в 10.3.1 с вариантными записями? Что, если вы явно передадите действительный TVarRec вместо неявного [123]?   -  person J...    schedule 15.04.2019
comment
Это еще один показатель обратной совместимости.   -  person Nasreddine Galfout    schedule 15.04.2019
comment
FWIW, код Токио также копирует массив, но этот код указан в начальной строке, а не в наследуемом. И Токио использует правильный размер. Но это ошибка в Rio, и о ней следует сообщить.   -  person Rudy Velthuis    schedule 15.04.2019
comment
О НЕТ, пожалуйста, не другая ошибка открытого массива! Некоторое время назад я обнаружил неприятную ошибку кодегена в Delphi 5, которая повреждает стек вызовов, когда открытые массивы используются в определенных условиях, и эта ошибка сильно повлияла на Indy (которая все еще поддерживает Delphi 5) и была основной PITA, которую нужно было обойти. до такой степени, что исправление было настолько уродливым, что я не хотел публиковать его публично. Если есть новая ошибка открытого массива, мне нужно снова проверить Indy :-( В Indy используется довольно много открытых массивов.   -  person Remy Lebeau    schedule 15.04.2019


Ответы (2)


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

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

procedure Setup(const aParams: array of const); 

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


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

person LU RD    schedule 15.04.2019
comment
Я заметил, что отчет на портале качества датируется 8 марта. - person Pep; 16.04.2019
comment
@pep Это не удивительно. Emb не умеет решать проблемы. У меня есть ошибка, которая, как они утверждают, была исправлена ​​в Токио, но тестовый код, который я создал для них, по-прежнему не работает. - person Graymatter; 16.04.2019

Эта ошибка НАМНОГО более обширна, она не обрабатывает короткие строки 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 !!!

person Lee Davis    schedule 24.01.2020