在嵌套方法中访问时被闭包捕获破坏的局部变量

Local variable broken by closure capture when accessed in nested method

我已经设法将这个问题简化为:

program Project1;
{$APPTYPE CONSOLE}

uses
  SysUtils, Threading;

procedure Foo(AString: string);
var
  LTask : ITask;
  capturedString : string;
  procedure Nested;
  begin
    try
      WriteLn('Nested : ' + capturedString); { ! EIntOverflow (Win32) here }
    except on E : Exception do
      WriteLn(E.Message);  
    end; 
  end;
begin
  capturedString := AString;
  WriteLn('Local : ' + capturedString);
  Nested;
  LTask := TTask.Create(
    procedure
      procedure AnonNested;
      begin
        WriteLn(capturedString); { Removing this eliminates the problem }
      end;
    begin
    end);
end;

begin
  Foo('foo');
  ReadLn;
end.

这里的 capturedString 变量在从嵌套方法中访问时被破坏。一个 Win32 编译引发 EIntOverflow,一个 Win64 编译写出一个(损坏的)空字符串 - 构建可以通过一些操作被激发到 AV 或其他异常,但在所有情况下,当进入Nested 程序。

这似乎只有在闭包中捕获 capturedString 时才会发生。

怎么了?

这似乎是 10.2 中已解决的编译器错误:

#RSP-18833: Capture by closure corrupts local variable used in nested method

解决方法是在匿名方法中使用第二个变量进行捕获:

procedure Foo(AString: string);
var
  LTask : ITask;
  capturedString, s2 : string;
  procedure Nested;
  begin
    try
      WriteLn('Nested : ' + capturedString);
    except on E : Exception do
      WriteLn(E.Message);  { !!! }
    end; 
  end;
begin
  capturedString := AString;
  s2 := capturedString;
  WriteLn('Local : ' + capturedString);
  Nested;
  LTask := TTask.Create(
    procedure
      procedure AnonNested;
      begin
        WriteLn(s2); { Capture another variable }
      end;
    begin
    end);
end;