diff --git a/src/libraries/System.IO/tests/BufferedStream/BufferedStreamTests.cs b/src/libraries/System.IO/tests/BufferedStream/BufferedStreamTests.cs index de9777729d407..f6a9834cf4469 100644 --- a/src/libraries/System.IO/tests/BufferedStream/BufferedStreamTests.cs +++ b/src/libraries/System.IO/tests/BufferedStream/BufferedStreamTests.cs @@ -53,6 +53,54 @@ public void BufferSize() Assert.Equal(1234, bufferedStream.BufferSize); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] + [OuterLoop] + [InlineData(int.MaxValue / 2 + 1)] + public void WriteFromByte_InputSizeLargerThanHalfOfMaxInt_ShouldSuccess(int inputSize) + { + byte[] bytes; + + try + { + bytes = new byte[inputSize]; + } + catch (OutOfMemoryException) + { + return; + } + + var writableStream = new WriteOnlyStream(); + using (var bs = new BufferedStream(writableStream)) + { + bs.Write(bytes, 0, inputSize); + Assert.Equal(inputSize, writableStream.Position); + } + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] + [OuterLoop] + [InlineData(int.MaxValue / 2 + 1)] + public void WriteFromSpan_InputSizeLargerThanHalfOfMaxInt_ShouldSuccess(int inputSize) + { + byte[] bytes; + + try + { + bytes = new byte[inputSize]; + } + catch (OutOfMemoryException) + { + return; + } + + var writableStream = new WriteOnlyStream(); + using (var bs = new BufferedStream(writableStream)) + { + bs.Write(new ReadOnlySpan(bytes)); + Assert.Equal(inputSize, writableStream.Position); + } + } + [Theory] [InlineData(true)] [InlineData(false)] @@ -369,4 +417,49 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati public override Task FlushAsync(CancellationToken cancellationToken) => throw new InvalidOperationException("Exception from FlushAsync"); } + + internal sealed class WriteOnlyStream : Stream + { + private long _pos; + + public override void Flush() + { + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + _pos += count; + } + + public override void Write(ReadOnlySpan buffer) + { + _pos += buffer.Length; + } + + public override bool CanRead => false; + public override bool CanSeek => false; + public override bool CanWrite => true; + public override long Length => _pos; + + public override long Position + { + get => _pos; + set => throw new NotSupportedException(); + } + } } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/BufferedStream.cs b/src/libraries/System.Private.CoreLib/src/System/IO/BufferedStream.cs index 14da1aa038b78..1b1f5ad44a46a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/BufferedStream.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/BufferedStream.cs @@ -889,7 +889,8 @@ public override void Write(byte[] buffer, int offset, int count) checked { // We do not expect buffer sizes big enough for an overflow, but if it happens, lets fail early: totalUserbytes = _writePos + count; - useBuffer = (totalUserbytes + count < (_bufferSize + _bufferSize)); + // Allow current totalUserbytes up to int.MaxValue by using uint arithmetic operation for totalUserbytes + count + useBuffer = ((uint)totalUserbytes + count < (_bufferSize + _bufferSize)); } if (useBuffer) @@ -959,7 +960,8 @@ public override void Write(ReadOnlySpan buffer) { // We do not expect buffer sizes big enough for an overflow, but if it happens, lets fail early: totalUserbytes = _writePos + buffer.Length; - useBuffer = (totalUserbytes + buffer.Length < (_bufferSize + _bufferSize)); + // Allow current totalUserbytes up to int.MaxValue by using uint arithmetic operation for totalUserbytes + buffer.Length + useBuffer = ((uint)totalUserbytes + buffer.Length < (_bufferSize + _bufferSize)); } if (useBuffer)