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

#delphi #delphi-10.3-rio

#delphi #delphi-10.3-rio

Вопрос:

Следующий код генерирует исключение (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.
 

Проблема, по-видимому, заключается в типе аргумента being array of const . Код по-прежнему завершается ошибкой для 64 бит, если мы изменим array of const на array of integer , поэтому кажется, что у нового компилятора Delphi есть проблема с массивами с неизвестным количеством параметров. Мы нашли трюк, позволяющий избежать ошибки компилятора, создав тип для array of integer , но этот трюк недоступен для того, что нам нужно array of const .

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

 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. Конечно, это ошибка компилятора. Я думаю, вам нужно отправить отчет в QualityPortal.

2. Еще одна причина не обновляться до 10.3.1, спасибо

3. @NasreddineGalfout, мы обновились из-за некоторых улучшений в поддержке High DPI, и первые впечатления в целом были хорошими, но эта проблема, похоже, является препятствием.

4. FWIW, токийский код также копирует массив, но этот код указан в начальной строке, а не в разделе унаследованный. И Tokyo использует правильный размер. Но это ошибка в Rio, и о ней следует сообщить .

5. О НЕТ, пожалуйста, только не еще одна ошибка с открытым массивом! Некоторое время назад я обнаружил неприятную ошибку codegen в Delphi 5, которая повреждает стек вызовов при использовании открытых массивов в определенных условиях, и эта ошибка сильно повлияла на Indy (который все еще поддерживает Delphi 5) и была серьезной проблемой для обхода, до такой степени, что «исправление» было настолькоуродливый Я не хотел публиковать его публично. Если есть новая ошибка с открытым массивом, мне нужно снова проверить Indy:-(В Indy используется довольно много открытых массивов.

Ответ №1:

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

Обходным путем является определение массива как a const в методе:

 procedure Setup(const aParams: array of const); 
 

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


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

Комментарии:

1. Я заметил, что отчет на портале качества датируется 8 марта.

2. @pep Это неудивительно. Emb не очень хороши в устранении проблем. У меня есть ошибка, которую, как они утверждают, исправили в Токио, но тестовый код, который я создал для них, по-прежнему терпит неудачу.

Ответ №2:

Эта ошибка ГОРАЗДО более обширна, она не обрабатывает измененные короткие строки для процедур / функций.

 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, установленным на $ 1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF!!