在Stream.read中将Longint计数与Int64大小一起使用是否危险? [英] Isn't it dangerous to use the Longint count with the Int64 size in Stream.read?

查看:111
本文介绍了在Stream.read中将Longint计数与Int64大小一起使用是否危险?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在检查 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆