我正在检查 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的过程中,我已经看到了很多这种模式。
我的理解是,在32位和64位Windows中,
Longint
是4个字节, Int64
是8个字节,因此,如果我的文件大小是$1 FFFF FFFF == 8589934591 == 8 GB
,则此例程将完全无法读取,因为最终计数将是$ FFFF FFFF == -1
。我不知道这是如何允许的,并且可能没有考虑在内(也许没有多少人试图读取8 GB以上的文件)。
最佳答案
我为此记录了一张票,并且它显然已在东京10.2中修复。这是64位编译的问题。
https://quality.embarcadero.com/browse/RSP-19094TCustomMemoryStream
和TMemoryStream
中的大文件(> 2GB)都存在问题。在TMemoryStream
中,问题很简单,因为需要将局部变量声明为NativeInt
而不是LongInt,并且Capacity需要更改为NativeInt
。在TCustomMemoryStream
中,它们更加微妙,因为这两种TCustomMemoryStream.Read
方法都将Int64
-Int64
计算的结果直接分配给LongInt
。即使此计算的结果不大于LongInt
,它也会溢出。
如果要在西雅图解决此问题,则需要执行代码 Hook ,替换System.Classes单元或推出自己的TMemoryStream
替换类。请记住,对于最后一个选项,您还需要替换TBytesStream
和TStringStream
,因为它们来自TMemoryStream
。
最后一个选项的另一个问题是第三方组件将没有您的“修复程序”。对于我们来说,我们只有几个地方需要处理大于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;
关于delphi - 在Stream.read中将Longint计数与Int64大小一起使用是否危险?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48039254/