我正在检查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以上的文件)。
答案 0 :(得分:1)
我为此记录了一张票,它显然已在东京10.2修复。这是64位编译的问题。
https://quality.embarcadero.com/browse/RSP-19094
TCustomMemoryStream
和TMemoryStream
中的大(> 2GB)文件存在问题。在TMemoryStream
中,问题很简单,因为需要将局部变量声明为NativeInt
而不是LongInt,并且需要将容量更改为NativeInt
。在TCustomMemoryStream
中,它们更加微妙,因为两种TCustomMemoryStream.Read
方法都会将Int64
- Int64
计算的结果直接分配给LongInt
。即使此计算结果不大于LongInt
,这也会溢出。
如果你想在西雅图解决这个问题,你需要做一个代码钩子,替换System.Classes单元或为TMemoryStream
推出你自己的替换类。请注意,对于最后一个选项,您还需要替换TBytesStream
和TStringStream
,因为这些来自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;