Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1944,7 +1944,7 @@
<value>startIndex cannot be larger than length of string.</value>
</data>
<data name="ArgumentOutOfRange_StreamLength" xml:space="preserve">
<value>Stream length must be non-negative and less than 2^31 - 1 - origin.</value>
<value>Stream length must be non-negative and less than the maximum array length (0x7FFFFFC7) - origin.</value>
Copy link
Member

Choose a reason for hiding this comment

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

There's been efforts to not hardcode 0x7FFFFFC7 and instead use Array.MaxLength. Can we pass $"0x{Array.MaxLength:X}" using SR.Format?

Suggested change
<value>Stream length must be non-negative and less than the maximum array length (0x7FFFFFC7) - origin.</value>
<value>Stream length must be non-negative and less than the maximum array length {0} - origin.</value>

Copy link
Member

Choose a reason for hiding this comment

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

Should this do something like the following instead, to help clarify that the value may change over time:

maximum array length (currently 0x{0})

Perhaps we could just explicitly use the text Array.MaxLength instead?

</data>
<data name="ArgumentOutOfRange_UIntPtrMax" xml:space="preserve">
<value>The length of the buffer must be less than the maximum UIntPtr value for your platform.</value>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers;
Expand Down Expand Up @@ -34,7 +34,7 @@ public class MemoryStream : Stream

private CachedCompletedInt32Task _lastReadTask; // The last successful task returned from ReadAsync

private const int MemStreamMaxLength = int.MaxValue;
private static int MemStreamMaxLength => Array.MaxLength;

public MemoryStream()
: this(0)
Expand Down Expand Up @@ -536,24 +536,24 @@ private long SeekCore(long offset, int loc)

// Sets the length of the stream to a given value. The new
// value must be nonnegative and less than the space remaining in
// the array, int.MaxValue - origin
// the array, MemStreamMaxLength - origin
// Origin is 0 in all cases other than a MemoryStream created on
// top of an existing array and a specific starting offset was passed
// into the MemoryStream constructor. The upper bounds prevents any
// situations where a stream may be created on top of an array then
// the stream is made longer than the maximum possible length of the
// array (int.MaxValue).
// array (MemStreamMaxLength).
//
public override void SetLength(long value)
{
if (value < 0 || value > int.MaxValue)
if (value < 0 || value > MemStreamMaxLength)
throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_StreamLength);

EnsureWriteable();

// Origin wasn't publicly exposed above.
Debug.Assert(MemStreamMaxLength == int.MaxValue); // Check parameter validation logic in this method if this fails.
if (value > (int.MaxValue - _origin))
Debug.Assert(MemStreamMaxLength == 0x7FFFFFC7); // Check parameter validation logic in this method if this fails.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Debug.Assert(MemStreamMaxLength == 0x7FFFFFC7); // Check parameter validation logic in this method if this fails.
Debug.Assert(MemStreamMaxLength == Array.MaxLength); // Check parameter validation logic in this method if this fails.

if (value > (MemStreamMaxLength - _origin))
throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_StreamLength);
Copy link
Member

Choose a reason for hiding this comment

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

I believe we will also need to update the ctor that takes capacity because it will keep throwing OOM while we throw OutOfRange everywhere else.


int newLength = _origin + (int)value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public void BinaryWriter_EncodingCtorAndWriteTests_Negative()
[Fact]
public void BinaryWriter_SeekTests()
{
int[] iArrLargeValues = new int[] { 10000, 100000, int.MaxValue / 200, int.MaxValue / 1000, short.MaxValue, int.MaxValue, int.MaxValue - 1, int.MaxValue / 2, int.MaxValue / 10, int.MaxValue / 100 };
int[] iArrLargeValues = new int[] { 10000, 100000, int.MaxValue / 200, int.MaxValue / 1000, short.MaxValue, Array.MaxLength, Array.MaxLength - 1, int.MaxValue / 2, int.MaxValue / 10, int.MaxValue / 100 };

BinaryWriter dw2 = null;
MemoryStream mstr = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ public void MemoryStream_SeekOverflow_Throws(SeekMode mode, int bufferSize, int
byte[] buffer = new byte[bufferSize];
using (MemoryStream ms = new MemoryStream(buffer, origin, buffer.Length - origin, true))
{
Seek(mode, ms, int.MaxValue - origin);
Assert.Throws<ArgumentOutOfRangeException>(() => Seek(mode, ms, (long)int.MaxValue - origin + 1));
Seek(mode, ms, Array.MaxLength - origin);
Assert.Throws<ArgumentOutOfRangeException>(() => Seek(mode, ms, (long)Array.MaxLength - origin + 1));
Assert.ThrowsAny<Exception>(() => Seek(mode, ms, long.MinValue + 1));
Assert.ThrowsAny<Exception>(() => Seek(mode, ms, long.MaxValue - 1));
}
Expand Down Expand Up @@ -146,6 +146,26 @@ public async Task DerivedMemoryStream_ReadWriteAsyncMemoryCalled_ReadWriteAsyncA
Assert.True(s.ReadArrayInvoked);
}

[Fact]
[SkipOnCI("Skipping on CI due to large memory allocation")]
public void MemoryStream_CapacityBoundaryChecks()
{
int MaxSupportedLength = Array.MaxLength;

using (var ms = new MemoryStream())
{
ms.Capacity = MaxSupportedLength - 1;
Assert.Equal(MaxSupportedLength - 1, ms.Capacity);

ms.Capacity = MaxSupportedLength;
Assert.Equal(MaxSupportedLength, ms.Capacity);

Assert.Throws<ArgumentOutOfRangeException>(() => ms.Capacity = MaxSupportedLength + 1);

Assert.Throws<ArgumentOutOfRangeException>(() => ms.Capacity = int.MaxValue);
}
}

private class ReadWriteOverridingMemoryStream : MemoryStream
{
public bool ReadArrayInvoked, WriteArrayInvoked;
Expand Down