Skip to content

Commit 5058ca8

Browse files
issue-50839 handle large int write input. (#53338)
* issue-50839 handle large int write input. * Also fix Write(ReadOnlySpan); Remove test case because it allocates large object * Fix comment: add tests. * Fix comment: use get_position to return _pos; Fix indentation issue. * Fix spacing Co-authored-by: Jeff Handley <[email protected]> Co-authored-by: Jeff Handley <[email protected]>
1 parent 668a39e commit 5058ca8

File tree

2 files changed

+97
-2
lines changed

2 files changed

+97
-2
lines changed

src/libraries/System.IO/tests/BufferedStream/BufferedStreamTests.cs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,54 @@ public void BufferSize()
5353
Assert.Equal(1234, bufferedStream.BufferSize);
5454
}
5555

56+
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))]
57+
[OuterLoop]
58+
[InlineData(int.MaxValue / 2 + 1)]
59+
public void WriteFromByte_InputSizeLargerThanHalfOfMaxInt_ShouldSuccess(int inputSize)
60+
{
61+
byte[] bytes;
62+
63+
try
64+
{
65+
bytes = new byte[inputSize];
66+
}
67+
catch (OutOfMemoryException)
68+
{
69+
return;
70+
}
71+
72+
var writableStream = new WriteOnlyStream();
73+
using (var bs = new BufferedStream(writableStream))
74+
{
75+
bs.Write(bytes, 0, inputSize);
76+
Assert.Equal(inputSize, writableStream.Position);
77+
}
78+
}
79+
80+
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))]
81+
[OuterLoop]
82+
[InlineData(int.MaxValue / 2 + 1)]
83+
public void WriteFromSpan_InputSizeLargerThanHalfOfMaxInt_ShouldSuccess(int inputSize)
84+
{
85+
byte[] bytes;
86+
87+
try
88+
{
89+
bytes = new byte[inputSize];
90+
}
91+
catch (OutOfMemoryException)
92+
{
93+
return;
94+
}
95+
96+
var writableStream = new WriteOnlyStream();
97+
using (var bs = new BufferedStream(writableStream))
98+
{
99+
bs.Write(new ReadOnlySpan<byte>(bytes));
100+
Assert.Equal(inputSize, writableStream.Position);
101+
}
102+
}
103+
56104
[Theory]
57105
[InlineData(true)]
58106
[InlineData(false)]
@@ -369,4 +417,49 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati
369417
public override Task FlushAsync(CancellationToken cancellationToken) =>
370418
throw new InvalidOperationException("Exception from FlushAsync");
371419
}
420+
421+
internal sealed class WriteOnlyStream : Stream
422+
{
423+
private long _pos;
424+
425+
public override void Flush()
426+
{
427+
}
428+
429+
public override int Read(byte[] buffer, int offset, int count)
430+
{
431+
throw new NotSupportedException();
432+
}
433+
434+
public override long Seek(long offset, SeekOrigin origin)
435+
{
436+
throw new NotSupportedException();
437+
}
438+
439+
public override void SetLength(long value)
440+
{
441+
throw new NotSupportedException();
442+
}
443+
444+
public override void Write(byte[] buffer, int offset, int count)
445+
{
446+
_pos += count;
447+
}
448+
449+
public override void Write(ReadOnlySpan<byte> buffer)
450+
{
451+
_pos += buffer.Length;
452+
}
453+
454+
public override bool CanRead => false;
455+
public override bool CanSeek => false;
456+
public override bool CanWrite => true;
457+
public override long Length => _pos;
458+
459+
public override long Position
460+
{
461+
get => _pos;
462+
set => throw new NotSupportedException();
463+
}
464+
}
372465
}

src/libraries/System.Private.CoreLib/src/System/IO/BufferedStream.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,8 @@ public override void Write(byte[] buffer, int offset, int count)
889889
checked
890890
{ // We do not expect buffer sizes big enough for an overflow, but if it happens, lets fail early:
891891
totalUserbytes = _writePos + count;
892-
useBuffer = (totalUserbytes + count < (_bufferSize + _bufferSize));
892+
// Allow current totalUserbytes up to int.MaxValue by using uint arithmetic operation for totalUserbytes + count
893+
useBuffer = ((uint)totalUserbytes + count < (_bufferSize + _bufferSize));
893894
}
894895

895896
if (useBuffer)
@@ -959,7 +960,8 @@ public override void Write(ReadOnlySpan<byte> buffer)
959960
{
960961
// We do not expect buffer sizes big enough for an overflow, but if it happens, lets fail early:
961962
totalUserbytes = _writePos + buffer.Length;
962-
useBuffer = (totalUserbytes + buffer.Length < (_bufferSize + _bufferSize));
963+
// Allow current totalUserbytes up to int.MaxValue by using uint arithmetic operation for totalUserbytes + buffer.Length
964+
useBuffer = ((uint)totalUserbytes + buffer.Length < (_bufferSize + _bufferSize));
963965
}
964966

965967
if (useBuffer)

0 commit comments

Comments
 (0)