TList <T>中的Delphi XE8错误,需要解决方法

Bof*_*ofA 38 delphi generics tlist delphi-xe8

升级到XE8后,我们的一些项目开始破坏数据.看起来像TList实现中的一个错误.

program XE8Bug1;
{$APPTYPE CONSOLE}

uses
  System.SysUtils, Generics.Collections;

type
  TRecord = record
    A: Integer;
    B: Int64;
  end;

var
  FRecord: TRecord;
  FList: TList<TRecord>;

begin
  FList := TList<TRecord>.Create;
  FRecord.A := 1;
  FList.Insert(0, FRecord);
  FRecord.A := 3;
  FList.Insert(1, FRecord);
  FRecord.A := 2;
  FList.Insert(1, FRecord);
  Writeln(IntToStr(FList[0].A) + IntToStr(FList[1].A) + IntToStr(FList[2].A));

end.
Run Code Online (Sandbox Code Playgroud)

此代码在XE7和之前(应该是)打印"123",但在XE8中打印"120".也许有人知道这个的quickfix?

更新:非正式修复在这里

Bof*_*ofA 32

我发现现在TList<T>.Insert方法调用TListHelper.InternalInsertX取决于数据大小,在我的情况下:

procedure TListHelper.InternalInsertN(AIndex: Integer; const Value);
var
  ElemSize: Integer;
begin
  CheckInsertRange(AIndex);

  InternalGrowCheck(FCount + 1);
  ElemSize := ElSize;
  if AIndex <> FCount then
    Move(PByte(FItems^)[AIndex * ElemSize], PByte(FItems^)[(AIndex * ElemSize) + 1], (FCount - AIndex) * ElemSize);
  Move(Value, PByte(FItems^)[AIndex * ElemSize], ElemSize);
  Inc(FCount);
  FNotify(Value, cnAdded);
end;
Run Code Online (Sandbox Code Playgroud)

我在第一次Move通话中看到了问题.目的地应该是:

PByte(FItems^)[(AIndex + 1) * ElemSize]
Run Code Online (Sandbox Code Playgroud)

PByte(FItems^)[(AIndex * ElemSize) + 1]
Run Code Online (Sandbox Code Playgroud)

Aaargh!

最后,我在我的项目中使用了Delphi XE7中的System.Generics.Defaults.pas和System.Generics.Collections.pas单元,现在所有工作都按预期工作.

更新:正如我所见,RTL没有受到影响,因为它不适TList<T>.Insert用于T大小> 8(或者我可能会错过什么?)

  • 通过恢复XE7实现进行修复并不是一个坏主意.你对此更加信任.是的,你可以修补这一种方法,但你不知道他们还有什么错吗? (3认同)