#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!!