web-dev-qa-db-ja.com

TList <T>のDelphiXE8バグ、回避策が必要

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.

このコードは、XE7以前では(本来あるべきことですが)「123」を出力しますが、XE8では「120」を出力します。多分誰かがこれのクイックフィックスを知っていますか?

更新:非公式の修正は ここ

38
BofA

私の場合、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;

最初のMove呼び出しで問題が発生しました。宛先は次のとおりです。

PByte(FItems^)[(AIndex + 1) * ElemSize]

ない

PByte(FItems^)[(AIndex * ElemSize) + 1]

アーグ!

最後に、プロジェクトでDelphi XE7のSystem.Generics.Defaults.pasユニットとSystem.Generics.Collections.pasユニットを使用しましたが、すべて期待どおりに機能するようになりました。

更新:私が見るように、RTLは影響を受けません。SizeOf> 8のTにTList<T>.Insertを使用しないためです(または何かを見逃している可能性がありますか?)

32
BofA