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;