У меня есть некоторые неожиданные нарушения доступа для кода Delphi, которые, по моему мнению, верны, но, похоже, ошибочны. Я могу уменьшить его до
procedure Run(Proc: TProc);
begin
Proc;
end;
procedure Test;
begin
Run(
procedure
var
S: PChar;
procedure Nested;
begin
Run(
procedure
begin
end);
S := 'Hello, world!';
end;
begin
Run(
procedure
begin
S := 'Hello';
end);
Nested;
ShowMessage(S);
end);
end;
Что происходит для меня, так это то, что S := 'Hello, world!'
хранится в неправильном месте. Из-за этого возникает либо нарушение доступа, либо ShowMessage(S)
показывает "Hello" (а иногда возникает нарушение прав доступа при освобождении объектов, используемых для реализации анонимных процедур).
Я использую Delphi XE, все обновления установлены.
Как я могу узнать, где это вызовет проблемы? Я знаю, как переписать мой код, чтобы избежать анонимных процедур, но мне трудно понять, в каких ситуациях они приводят к неправильному коду, поэтому я не знаю, где их избежать.
Мне было бы интересно узнать, исправлено ли это в более поздних версиях Delphi, но не более чем интересно, обновление на данный момент не является вариантом.
В QC, в последнем отчете я могу найти аналогичный # 91876, но это разрешено в Delphi XE.
Обновление
На основе комментариев AlexSC с небольшой модификацией:
...
procedure Nested;
begin
Run(
procedure
begin
S := S;
end);
S := 'Hello, world!';
end;
...
работает.
Сгенерированный машинный код для
S := 'Hello, world!';
в неудачной программе
ScratchForm.pas.44: S := 'Hello, world!';
004BD971 B89CD94B00 mov eax,$004bd99c
004BD976 894524 mov [ebp+$24],eax
тогда как правильная версия
ScratchForm.pas.45: S := 'Hello, world!';
004BD981 B8B0D94B00 mov eax,$004bd9b0
004BD986 8B5508 mov edx,[ebp+$08]
004BD989 8B52FC mov edx,[edx-$04]
004BD98C 89420C mov [edx+$0c],eax
Сгенерированный код в отказоустойчивой программе не видит, что S
был перемещен в класс, сгенерированный компилятором, [ebp+$24]
- это , к которому обращаются внешние локальные переменные вложенных методов, как локальные переменные доступны.