在Stream.read中将Longint计数与Int64大小一起使用是否危险? [英] Isn't it dangerous to use the Longint count with the Int64 size in Stream.read?
问题描述
我正在检查 TMemoryStream
类,并找到以下例程:
I was examining the TMemoryStream
class and found the following routine:
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的过程中,我经常看到这种模式。
I have seen this pattern a lot where an Int64 is assigned to a Longint.
我的理解是 Longint
是四个字节,并且 Int64
在32位和64位Windows中均为8个字节,因此如果我的文件大小为 $ 1 FFFF FFFF == 8589934591 == 8 GB
,则此例程将无法读取,因为最终计数为 $ FFFF FFFF == -1
。
My understanding is that Longint
is four bytes and Int64
is eight bytes in both 32-bit and 64-bit Windows, so if my file size is $1 FFFF FFFF == 8589934591 == 8 GB
then this routine will simply fail to read because the final count will be $ FFFF FFFF == -1
.
我不知道这是如何允许的,也许没有考虑(也许没有多少人试图读取8 GB以上的文件)。
I do not understand how this is allowed and maybe not taken into consideration (maybe not many people are trying to read an 8+ GB file).
推荐答案
我为此记录了一张票,并且它显然已在Tokyo 10.2中修复。这是64位编译的问题。
I logged a ticket for this and it has apparently been fixed in Tokyo 10.2. This is an issue for 64 bit compilation.
https://quality.embarcadero.com/browse/RSP-19094
两个<$>中的大文件(> 2GB)都有问题c $ c> TCustomMemoryStream 和 TMemoryStream
。在 TMemoryStream
中,问题很简单,因为局部变量需要声明为 NativeInt
而不是LongInt,而Capacity需要是更改为 NativeInt
。在 TCustomMemoryStream
中,它们更加微妙,因为这两个 TCustomMemoryStream.Read
方法都分配了 Int64的结果。
- Int64
直接计算为 LongInt
。即使此计算结果不大于 LongInt
,也会溢出。
There are problems with large (>2GB) files in both TCustomMemoryStream
and TMemoryStream
. In TMemoryStream
the issues are simple as the local variables need to be declared as NativeInt
instead of LongInt's and Capacity needs to be changed to an NativeInt
. In TCustomMemoryStream
they are more subtle because both TCustomMemoryStream.Read
methods assign the result of an Int64
- Int64
calculation directly to a LongInt
. This will overflow even when the result of this calculation isn't larger than a LongInt
.
如果要在Seattle中解决此问题,您将需要执行代码挂钩,替换System.Classes单元或推出自己的 TMemoryStream
替换类。请记住,对于最后一个选项,您还需要替换 TBytesStream
和 TStringStream
,因为它们均来自 TMemoryStream
。
If you want to fix this in Seattle then you will need to either do a code hook, replace the System.Classes unit or roll out your own replacement class for TMemoryStream
. Bear in mind that for the last option, you will need to also replace TBytesStream
and TStringStream
because these descend from TMemoryStream
.
最后一个选项的另一个问题是第三方组件没有您的修复程序。对于我们来说,我们只有几个地方需要处理大于2GB的文件,因此我们将它们切换了。
The other problem with the the last option is that third party components won't have your "fixes". For us, we only had a couple of places that needed to work with files larger than 2GB so we switched those across.
TCustomMemoryStream.Read的修复(必须是两种方法都将如下所示:
The fixes for TCustomMemoryStream.Read (must be to both methods) will look something like this:
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;
这篇关于在Stream.read中将Longint计数与Int64大小一起使用是否危险?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!