diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
index 289b1df2b90512..23f8538a1dc16b 100644
--- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
+++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
@@ -1944,7 +1944,7 @@
startIndex cannot be larger than length of string.
- Stream length must be non-negative and less than 2^31 - 1 - origin.
+ Stream length must be non-negative and less than the maximum array length (0x7FFFFFC7) - origin.
The length of the buffer must be less than the maximum UIntPtr value for your platform.
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs b/src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs
index fc645292c91d58..05480a61c72b5c 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs
@@ -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;
@@ -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)
@@ -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.
+ if (value > (MemStreamMaxLength - _origin))
throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_StreamLength);
int newLength = _origin + (int)value;
diff --git a/src/libraries/System.Runtime/tests/System.IO.Tests/BinaryWriter/BinaryWriterTests.cs b/src/libraries/System.Runtime/tests/System.IO.Tests/BinaryWriter/BinaryWriterTests.cs
index 1ed29de3009c22..1d1ed698b0dbdf 100644
--- a/src/libraries/System.Runtime/tests/System.IO.Tests/BinaryWriter/BinaryWriterTests.cs
+++ b/src/libraries/System.Runtime/tests/System.IO.Tests/BinaryWriter/BinaryWriterTests.cs
@@ -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;
diff --git a/src/libraries/System.Runtime/tests/System.IO.Tests/MemoryStream/MemoryStreamTests.cs b/src/libraries/System.Runtime/tests/System.IO.Tests/MemoryStream/MemoryStreamTests.cs
index 23d4b88c3da8d2..ee77811f224290 100644
--- a/src/libraries/System.Runtime/tests/System.IO.Tests/MemoryStream/MemoryStreamTests.cs
+++ b/src/libraries/System.Runtime/tests/System.IO.Tests/MemoryStream/MemoryStreamTests.cs
@@ -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(() => Seek(mode, ms, (long)int.MaxValue - origin + 1));
+ Seek(mode, ms, Array.MaxLength - origin);
+ Assert.Throws(() => Seek(mode, ms, (long)Array.MaxLength - origin + 1));
Assert.ThrowsAny(() => Seek(mode, ms, long.MinValue + 1));
Assert.ThrowsAny(() => Seek(mode, ms, long.MaxValue - 1));
}
@@ -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(() => ms.Capacity = MaxSupportedLength + 1);
+
+ Assert.Throws(() => ms.Capacity = int.MaxValue);
+ }
+ }
+
private class ReadWriteOverridingMemoryStream : MemoryStream
{
public bool ReadArrayInvoked, WriteArrayInvoked;