-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
(Edit: I updated the issue report, as not only ReadByte() is affected but WriteByte() as well).
Description
When creating a non-resizable MemoryStream from an array region whose start/origin index is larger than zero, the MemoryStream.Position value can be set in a way that leads to IndexOutOfRangeException when calling MemoryStream.ReadByte() or MemoryStream.WriteByte() .
This is due to the assignment of the private _position field in the MemoryStream.Position set accessor:
| _position = _origin + (int)value; |
which can lead to _position becoming negative.
Both the ReadByte() and WriteByte() method, however, do not test for _position being negative before using it as an index into the _buffer byte array, thus being vulnerable to causing IndexOutOfRangeException.
ReadByte():
runtime/src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs
Lines 430 to 433 in 57608c3
| if (_position >= _length) | |
| return -1; | |
| return _buffer[_position++]; |
WriteByte():
runtime/src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs
Lines 736 to 754 in 57608c3
| if (_position >= _length) | |
| { | |
| int newLength = _position + 1; | |
| bool mustZero = _position > _length; | |
| if (newLength >= _capacity) | |
| { | |
| bool allocatedNewArray = EnsureCapacity(newLength); | |
| if (allocatedNewArray) | |
| { | |
| mustZero = false; | |
| } | |
| } | |
| if (mustZero) | |
| { | |
| Array.Clear(_buffer, _length, _position - _length); | |
| } | |
| _length = newLength; | |
| } | |
| _buffer[_position++] = value; |
Reproduction Steps
byte[] buffer = new byte[100];
using var ms = new System.IO.MemoryStream(buffer, 10, buffer.Length - 10, true);
//
// Let the private MemoryStream._position field overflow
//
var newPosition = int.MaxValue - 9;
ms.Position = newPosition;
System.Console.WriteLine("ms.Position == newPosition: " + (ms.Position == newPosition));
System.Console.WriteLine();
System.Console.WriteLine("ReadByte");
try
{
var b = ms.ReadByte();
System.Console.WriteLine("ms.ReadByte() returned " + b);
}
catch (System.Exception ex)
{
System.Console.WriteLine(ex);
}
System.Console.WriteLine();
System.Console.WriteLine("WriteByte");
try
{
ms.WriteByte(0);
}
catch (System.Exception ex)
{
System.Console.WriteLine(ex);
}Expected behavior
Expected result/output:
ms.Position == newPosition: True
ReadByte
ms.ReadByte() returned -1
WriteByte
System.NotSupportedException: Memory stream is not expandable.
...
Actual behavior
Actual result/output:
ms.Position == newPosition: True
ReadByte
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at System.IO.MemoryStream.ReadByte()
...
WriteByte
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at System.IO.MemoryStream.WriteByte(Byte value)
...
Regression?
No response
Known Workarounds
No response
Configuration
.NET 8 Preview 3 (https://dotnetfiddle.net/V1POV0)
.NET Framework 4.7.2 (https://dotnetfiddle.net/gM2LkH)
Considering that the bug is already present and reproducible in the old .NET Framework 4.7.2, it's reasonable to assume that at least any .NET version following Framework 4.7.2 is also affected by this issue.
Other information
No response