在Stream.read中使用Int64大小的Longint计数是不是很危险?

时间:2017-12-31 01:27:08

标签: delphi delphi-10-seattle

我正在检查TMemoryStream课程并找到以下例程:

procedure TMemoryStream.LoadFromStream(Stream: TStream);
var
  Count: Longint;
begin
  Stream.Position := 0;
  Count := Stream.Size; // <-- assigning Int64 to Longint
  SetSize(Count);
  if Count <> 0 then Stream.ReadBuffer(FMemory^, Count);
end;

我已经看到了很多将Int64分配给Longint的模式。

我的理解是Longint是4个字节,Int64在32位和64位Windows中都是8个字节,所以如果我的文件大小是$1 FFFF FFFF == 8589934591 == 8 GB那么这个例程将根本无法阅读,因为最终的计数将是$ FFFF FFFF == -1

我不明白这是怎么允许的,也许不予考虑(可能没有多少人试图读取8 GB以上的文件)。

1 个答案:

答案 0 :(得分:1)

我为此记录了一张票,它显然已在东京10.2修复。这是64位编译的问题。

https://quality.embarcadero.com/browse/RSP-19094

TCustomMemoryStreamTMemoryStream中的大(> 2GB)文件存在问题。在TMemoryStream中,问题很简单,因为需要将局部变量声明为NativeInt而不是LongInt,并且需要将容量更改为NativeInt。在TCustomMemoryStream中,它们更加微妙,因为两种TCustomMemoryStream.Read方法都会将Int64 - Int64计算的结果直接分配给LongInt。即使此计算结果不大于LongInt,这也会溢出。

如果你想在西雅图解决这个问题,你需要做一个代码钩子,替换System.Classes单元或为TMemoryStream推出你自己的替换类。请注意,对于最后一个选项,您还需要替换TBytesStreamTStringStream,因为这些来自TMemoryStream

最后一个选项的另一个问题是,第三方组件不会有#34;修复&#34;。对于我们来说,我们只有几个地方需要处理大于2GB的文件,所以我们将它们切换到了。

TCustomMemoryStream.Read的修复(必须是两个方法)看起来像这样:

function TCustomMemoryStream.Read(var Buffer; Count: Longint): Longint;
{ These 2 lines are new }
var
  remaining: Int64;
begin
  if (FPosition >= 0) and (Count >= 0) then
  begin
    remaining{Result} := FSize - FPosition;
    if remaining{Result} > 0 then
    begin
      if remaining{Result} > Count then 
        Result := Count
      else
        Result := remaining;
      Move((PByte(FMemory) + FPosition)^, Buffer, Result);
      Inc(FPosition, Result);
      Exit;
    end;
  end;
  Result := 0;
end;