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
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
.
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
.
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.
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;
TMemoryStream
doesn't support allocating more than 2GB, not even in a 64bit application. So, even thoughTStream.Size
is anInt64
,TMemoryStream
limits it to 2GB. So you can't load a >2GB file into aTMemoryStream
. If you need that (why?), you will have to write your own stream class that supports >2GB, or find a 3rd party stream class that does. – DiadelphousTMemoryStream
was never updated to support >2GB even after the RTL memory manager was updated to support 64bit allocations. Feel free to file a bug report with Embarcadero. – DiadelphousTMemoryStream
as an example. But the problem stands for any combination ofInt64
andLongint
. Failure to pick up these discrepancies leads to surprise production bugs. The point of a strongly typed language is to try avoid them. A suitable compiler warning is not an unreasonable expectation. – Tameikaprocedure SetSize(NewSize: Longint); override;
. DeclaringFSize, FPosition: NativeInt;
is no use if the value you feed in is truncated toLongint
. That same problem is there in Seattle. – Windowpane