Skip to content

Conversation

@adamsitnik
Copy link
Member

@adamsitnik adamsitnik commented Oct 15, 2021

fixes #60430

For the following code:

_readPos = (int)(newPos - (oldPos - _readPos));

For a newPos > 4GB and small oldPos and _readPos we had an int32 overflow. Sample C# app to demonstrate the problem:

long oldPos = 10L; // first read started at Position=10
long newPos = (1L << 32) + oldPos; // new position is larger than 4 GB
int _readPos = 5; // 5 bytes were read from the buffer so far
int readPosInteger = (int)(newPos - (oldPos - _readPos));
long readPosLong = (newPos - (oldPos - _readPos));

Console.WriteLine(readPosInteger);
Console.WriteLine(readPosLong);
5
4294967301

It seems to be a very old bug that was always present in BufferedStream and I've copied it to BufferedFileStreamStrategy in 6.0.

1.0 branch:

https://github.com/dotnet/corefx/blob/c74ea81f2ddad07dc05d695d8244fb2ece7e398d/src/System.IO/src/System/IO/BufferedStream.cs#L1053-L1054

Since we are very close to 6.0 release I've focused on making smallest possible change instead of doing a refactor and providing code that would look better but would be harder to review.

@ghost
Copy link

ghost commented Oct 15, 2021

Tagging subscribers to this area: @dotnet/area-system-io
See info in area-owners.md if you want to be subscribed.

Issue Details

fixes #60430

Author: adamsitnik
Assignees: -
Labels:

area-System.IO

Milestone: -

@adamsitnik
Copy link
Member Author

/backport to release/6.0

@github-actions
Copy link
Contributor

Started backporting to release/6.0: https://github.com/dotnet/runtime/actions/runs/1345172097

Copy link
Member

@jozkee jozkee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found only nits, I also tried to see if I could find more overflow issues in BufferedFileStreamStrategy but didn't see any.

Thanks, @adamsitnik.

using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
stream.Seek(position1, SeekOrigin.Begin);
stream.Write(data1, 0, data1.Length);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Use Span-based overloads

Suggested change
stream.Write(data1, 0, data1.Length);
stream.Write(data1);

stream.Write(data1, 0, data1.Length);

stream.Seek(position2, SeekOrigin.Begin);
stream.Write(data2, 0, data2.Length);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Suggested change
stream.Write(data2, 0, data2.Length);
stream.Write(data2);

Comment on lines +50 to +59
using (var stream = new BufferedStream(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None, bufferSize: 0)))
{
stream.Seek(position1, SeekOrigin.Begin);
Assert.Equal(buffer.Length, stream.Read(buffer));
Assert.Equal(data1, buffer);

stream.Seek(position2, SeekOrigin.Begin);
Assert.Equal(buffer.Length, stream.Read(buffer));
Assert.Equal(data2, buffer);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this piece of code should be a separate test in src/libraries/System.IO/tests/BufferedStream/BufferedStreamTests.cs

@jozkee
Copy link
Member

jozkee commented Oct 15, 2021

Merging to keep the backport PR as a clean port of this one i.e: to not have different commits.

CI issue ReadAllBytes_NonSeekableFileStream_InWindows is known #60427.

@jozkee jozkee merged commit ea58ba6 into dotnet:main Oct 15, 2021
@adamsitnik adamsitnik deleted the bug60430 branch October 16, 2021 08:58
@ghost ghost locked as resolved and limited conversation to collaborators Nov 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Disk files larger than 4GB may not be read properly

3 participants