Skip to content

Commit c1c9744

Browse files
committed
Add a Stream buffer validation helper
1 parent b803932 commit c1c9744

File tree

5 files changed

+77
-90
lines changed

5 files changed

+77
-90
lines changed

src/Renci.SshNet/Common/ChannelInputStream.cs

+4-11
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,10 @@ public override int Read(byte[] buffer, int offset, int count)
101101
/// <exception cref="ArgumentOutOfRangeException">offset or count is negative.</exception>
102102
public override void Write(byte[] buffer, int offset, int count)
103103
{
104-
ThrowHelper.ThrowIfNull(buffer);
105-
106-
if (offset + count > buffer.Length)
107-
{
108-
throw new ArgumentException("The sum of offset and count is greater than the buffer length.");
109-
}
110-
111-
if (offset < 0 || count < 0)
112-
{
113-
throw new ArgumentOutOfRangeException(nameof(offset), "offset or count is negative.");
114-
}
104+
#if !NET
105+
ThrowHelper.
106+
#endif
107+
ValidateBufferArguments(buffer, offset, count);
115108

116109
ThrowHelper.ThrowObjectDisposedIf(_isDisposed, this);
117110

src/Renci.SshNet/Common/PipeStream.cs

+10
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ public override void SetLength(long value)
6464
/// <inheritdoc/>
6565
public override int Read(byte[] buffer, int offset, int count)
6666
{
67+
#if !NET
68+
ThrowHelper.
69+
#endif
70+
ValidateBufferArguments(buffer, offset, count);
71+
6772
lock (_sync)
6873
{
6974
while (_head == _tail && !_disposed)
@@ -88,6 +93,11 @@ public override int Read(byte[] buffer, int offset, int count)
8893
/// <inheritdoc/>
8994
public override void Write(byte[] buffer, int offset, int count)
9095
{
96+
#if !NET
97+
ThrowHelper.
98+
#endif
99+
ValidateBufferArguments(buffer, offset, count);
100+
91101
lock (_sync)
92102
{
93103
ThrowHelper.ThrowObjectDisposedIf(_disposed, this);

src/Renci.SshNet/Common/ThrowHelper.cs

+34
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,39 @@ static void Throw(string? argument, string? paramName)
7979
}
8080
#endif
8181
}
82+
83+
#if !NET
84+
// A rough copy of
85+
// https://github.com/dotnet/runtime/blob/1d1bf92fcf43aa6981804dc53c5174445069c9e4/src/libraries/System.Private.CoreLib/src/System/IO/Stream.cs#L960C13-L974C10
86+
// for lower targets.
87+
public static void ValidateBufferArguments(byte[] buffer, int offset, int count)
88+
{
89+
ThrowIfNull(buffer);
90+
91+
if (offset < 0)
92+
{
93+
Throw();
94+
95+
[DoesNotReturn]
96+
static void Throw()
97+
{
98+
throw new ArgumentOutOfRangeException(nameof(offset), "Non-negative number required.");
99+
}
100+
}
101+
102+
if ((uint)count > buffer.Length - offset)
103+
{
104+
Throw();
105+
106+
[DoesNotReturn]
107+
static void Throw()
108+
{
109+
throw new ArgumentOutOfRangeException(
110+
nameof(count),
111+
"Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.");
112+
}
113+
}
114+
}
115+
#endif
82116
}
83117
}

src/Renci.SshNet/Sftp/SftpFileStream.cs

+19-79
Original file line numberDiff line numberDiff line change
@@ -511,28 +511,12 @@ public override Task FlushAsync(CancellationToken cancellationToken)
511511
/// </remarks>
512512
public override int Read(byte[] buffer, int offset, int count)
513513
{
514-
var readLen = 0;
515-
516-
ThrowHelper.ThrowIfNull(buffer);
517-
518-
#if NET
519-
ArgumentOutOfRangeException.ThrowIfNegative(offset);
520-
ArgumentOutOfRangeException.ThrowIfNegative(count);
521-
#else
522-
if (offset < 0)
523-
{
524-
throw new ArgumentOutOfRangeException(nameof(offset));
525-
}
526-
527-
if (count < 0)
528-
{
529-
throw new ArgumentOutOfRangeException(nameof(count));
530-
}
514+
#if !NET
515+
ThrowHelper.
531516
#endif
532-
if ((buffer.Length - offset) < count)
533-
{
534-
throw new ArgumentException("Invalid array range.");
535-
}
517+
ValidateBufferArguments(buffer, offset, count);
518+
519+
var readLen = 0;
536520

537521
// Lock down the file stream while we do this.
538522
lock (_lock)
@@ -653,28 +637,14 @@ public override int Read(byte[] buffer, int offset, int count)
653637
/// <returns>A <see cref="Task" /> that represents the asynchronous read operation.</returns>
654638
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
655639
{
656-
var readLen = 0;
657-
658-
ThrowHelper.ThrowIfNull(buffer);
640+
#if !NET
641+
ThrowHelper.
642+
#endif
643+
ValidateBufferArguments(buffer, offset, count);
659644

660-
#if NET
661-
ArgumentOutOfRangeException.ThrowIfNegative(offset);
662-
ArgumentOutOfRangeException.ThrowIfNegative(count);
663-
#else
664-
if (offset < 0)
665-
{
666-
throw new ArgumentOutOfRangeException(nameof(offset));
667-
}
645+
cancellationToken.ThrowIfCancellationRequested();
668646

669-
if (count < 0)
670-
{
671-
throw new ArgumentOutOfRangeException(nameof(count));
672-
}
673-
#endif
674-
if ((buffer.Length - offset) < count)
675-
{
676-
throw new ArgumentException("Invalid array range.");
677-
}
647+
var readLen = 0;
678648

679649
CheckSessionIsOpen();
680650

@@ -1005,26 +975,10 @@ public override void SetLength(long value)
1005975
/// <exception cref="ObjectDisposedException">Methods were called after the stream was closed.</exception>
1006976
public override void Write(byte[] buffer, int offset, int count)
1007977
{
1008-
ThrowHelper.ThrowIfNull(buffer);
1009-
1010-
#if NET
1011-
ArgumentOutOfRangeException.ThrowIfNegative(offset);
1012-
ArgumentOutOfRangeException.ThrowIfNegative(count);
1013-
#else
1014-
if (offset < 0)
1015-
{
1016-
throw new ArgumentOutOfRangeException(nameof(offset));
1017-
}
1018-
1019-
if (count < 0)
1020-
{
1021-
throw new ArgumentOutOfRangeException(nameof(count));
1022-
}
978+
#if !NET
979+
ThrowHelper.
1023980
#endif
1024-
if ((buffer.Length - offset) < count)
1025-
{
1026-
throw new ArgumentException("Invalid array range.");
1027-
}
981+
ValidateBufferArguments(buffer, offset, count);
1028982

1029983
// Lock down the file stream while we do this.
1030984
lock (_lock)
@@ -1105,26 +1059,12 @@ public override void Write(byte[] buffer, int offset, int count)
11051059
/// <exception cref="ObjectDisposedException">Methods were called after the stream was closed.</exception>
11061060
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
11071061
{
1108-
ThrowHelper.ThrowIfNull(buffer);
1109-
1110-
#if NET
1111-
ArgumentOutOfRangeException.ThrowIfNegative(offset);
1112-
ArgumentOutOfRangeException.ThrowIfNegative(count);
1113-
#else
1114-
if (offset < 0)
1115-
{
1116-
throw new ArgumentOutOfRangeException(nameof(offset));
1117-
}
1118-
1119-
if (count < 0)
1120-
{
1121-
throw new ArgumentOutOfRangeException(nameof(count));
1122-
}
1062+
#if !NET
1063+
ThrowHelper.
11231064
#endif
1124-
if ((buffer.Length - offset) < count)
1125-
{
1126-
throw new ArgumentException("Invalid array range.");
1127-
}
1065+
ValidateBufferArguments(buffer, offset, count);
1066+
1067+
cancellationToken.ThrowIfCancellationRequested();
11281068

11291069
CheckSessionIsOpen();
11301070

src/Renci.SshNet/ShellStream.cs

+10
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,11 @@ public string Read()
789789
/// <inheritdoc/>
790790
public override int Read(byte[] buffer, int offset, int count)
791791
{
792+
#if !NET
793+
ThrowHelper.
794+
#endif
795+
ValidateBufferArguments(buffer, offset, count);
796+
792797
lock (_sync)
793798
{
794799
while (_readHead == _readTail && !_disposed)
@@ -835,6 +840,11 @@ public void Write(string? text)
835840
/// <inheritdoc/>
836841
public override void Write(byte[] buffer, int offset, int count)
837842
{
843+
#if !NET
844+
ThrowHelper.
845+
#endif
846+
ValidateBufferArguments(buffer, offset, count);
847+
838848
ThrowHelper.ThrowObjectDisposedIf(_disposed, this);
839849

840850
while (count > 0)

0 commit comments

Comments
 (0)