Add a Stream buffer validation helper (#1605)

* Add a Stream buffer validation helper

* add ThrowHelper.ThrowIfNegative
This commit is contained in:
Rob Hague
2025-03-25 12:45:18 +01:00
committed by GitHub
parent bb3beeb6c5
commit 484afbdf9d
7 changed files with 88 additions and 107 deletions
+4 -11
View File
@@ -101,17 +101,10 @@ namespace Renci.SshNet.Common
/// <exception cref="ArgumentOutOfRangeException">offset or count is negative.</exception>
public override void Write(byte[] buffer, int offset, int count)
{
ThrowHelper.ThrowIfNull(buffer);
if (offset + count > buffer.Length)
{
throw new ArgumentException("The sum of offset and count is greater than the buffer length.");
}
if (offset < 0 || count < 0)
{
throw new ArgumentOutOfRangeException(nameof(offset), "offset or count is negative.");
}
#if !NET
ThrowHelper.
#endif
ValidateBufferArguments(buffer, offset, count);
ThrowHelper.ThrowObjectDisposedIf(_isDisposed, this);
+1 -5
View File
@@ -15,11 +15,7 @@ namespace Renci.SshNet.Common
public static string Create(byte[] data, int indentLevel)
{
ThrowHelper.ThrowIfNull(data);
if (indentLevel < 0)
{
throw new ArgumentOutOfRangeException(nameof(indentLevel), "Cannot be less than zero.");
}
ThrowHelper.ThrowIfNegative(indentLevel);
const int lineWidth = 16;
+10
View File
@@ -64,6 +64,11 @@ namespace Renci.SshNet.Common
/// <inheritdoc/>
public override int Read(byte[] buffer, int offset, int count)
{
#if !NET
ThrowHelper.
#endif
ValidateBufferArguments(buffer, offset, count);
lock (_sync)
{
while (_head == _tail && !_disposed)
@@ -88,6 +93,11 @@ namespace Renci.SshNet.Common
/// <inheritdoc/>
public override void Write(byte[] buffer, int offset, int count)
{
#if !NET
ThrowHelper.
#endif
ValidateBufferArguments(buffer, offset, count);
lock (_sync)
{
ThrowHelper.ThrowObjectDisposedIf(_disposed, this);
+42
View File
@@ -77,6 +77,48 @@ namespace Renci.SshNet.Common
throw new ArgumentException("The value cannot be an empty string.", paramName);
}
}
#endif
}
#if !NET
// A rough copy of
// https://github.com/dotnet/runtime/blob/1d1bf92fcf43aa6981804dc53c5174445069c9e4/src/libraries/System.Private.CoreLib/src/System/IO/Stream.cs#L960C13-L974C10
// for lower targets.
public static void ValidateBufferArguments(byte[] buffer, int offset, int count)
{
ThrowIfNull(buffer);
ThrowIfNegative(offset);
if ((uint)count > buffer.Length - offset)
{
Throw();
[DoesNotReturn]
static void Throw()
{
throw new ArgumentOutOfRangeException(
nameof(count),
"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.");
}
}
}
#endif
public static void ThrowIfNegative(long value, [CallerArgumentExpression(nameof(value))] string? paramName = null)
{
#if NET
ArgumentOutOfRangeException.ThrowIfNegative(value, paramName);
#else
if (value < 0)
{
Throw(value, paramName);
[DoesNotReturn]
static void Throw(long value, string? paramName)
{
throw new ArgumentOutOfRangeException(paramName, value, "Value must be non-negative.");
}
}
#endif
}
}
+21 -88
View File
@@ -511,28 +511,12 @@ namespace Renci.SshNet.Sftp
/// </remarks>
public override int Read(byte[] buffer, int offset, int count)
{
var readLen = 0;
ThrowHelper.ThrowIfNull(buffer);
#if NET
ArgumentOutOfRangeException.ThrowIfNegative(offset);
ArgumentOutOfRangeException.ThrowIfNegative(count);
#else
if (offset < 0)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
#if !NET
ThrowHelper.
#endif
if ((buffer.Length - offset) < count)
{
throw new ArgumentException("Invalid array range.");
}
ValidateBufferArguments(buffer, offset, count);
var readLen = 0;
// Lock down the file stream while we do this.
lock (_lock)
@@ -653,28 +637,14 @@ namespace Renci.SshNet.Sftp
/// <returns>A <see cref="Task" /> that represents the asynchronous read operation.</returns>
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
var readLen = 0;
ThrowHelper.ThrowIfNull(buffer);
#if NET
ArgumentOutOfRangeException.ThrowIfNegative(offset);
ArgumentOutOfRangeException.ThrowIfNegative(count);
#else
if (offset < 0)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
#if !NET
ThrowHelper.
#endif
if ((buffer.Length - offset) < count)
{
throw new ArgumentException("Invalid array range.");
}
ValidateBufferArguments(buffer, offset, count);
cancellationToken.ThrowIfCancellationRequested();
var readLen = 0;
CheckSessionIsOpen();
@@ -952,14 +922,7 @@ namespace Renci.SshNet.Sftp
/// </remarks>
public override void SetLength(long value)
{
#if NET
ArgumentOutOfRangeException.ThrowIfNegative(value);
#else
if (value < 0)
{
throw new ArgumentOutOfRangeException(nameof(value));
}
#endif
ThrowHelper.ThrowIfNegative(value);
// Lock down the file stream while we do this.
lock (_lock)
@@ -1005,26 +968,10 @@ namespace Renci.SshNet.Sftp
/// <exception cref="ObjectDisposedException">Methods were called after the stream was closed.</exception>
public override void Write(byte[] buffer, int offset, int count)
{
ThrowHelper.ThrowIfNull(buffer);
#if NET
ArgumentOutOfRangeException.ThrowIfNegative(offset);
ArgumentOutOfRangeException.ThrowIfNegative(count);
#else
if (offset < 0)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
#if !NET
ThrowHelper.
#endif
if ((buffer.Length - offset) < count)
{
throw new ArgumentException("Invalid array range.");
}
ValidateBufferArguments(buffer, offset, count);
// Lock down the file stream while we do this.
lock (_lock)
@@ -1105,26 +1052,12 @@ namespace Renci.SshNet.Sftp
/// <exception cref="ObjectDisposedException">Methods were called after the stream was closed.</exception>
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
ThrowHelper.ThrowIfNull(buffer);
#if NET
ArgumentOutOfRangeException.ThrowIfNegative(offset);
ArgumentOutOfRangeException.ThrowIfNegative(count);
#else
if (offset < 0)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
#if !NET
ThrowHelper.
#endif
if ((buffer.Length - offset) < count)
{
throw new ArgumentException("Invalid array range.");
}
ValidateBufferArguments(buffer, offset, count);
cancellationToken.ThrowIfCancellationRequested();
CheckSessionIsOpen();
+10
View File
@@ -789,6 +789,11 @@ namespace Renci.SshNet
/// <inheritdoc/>
public override int Read(byte[] buffer, int offset, int count)
{
#if !NET
ThrowHelper.
#endif
ValidateBufferArguments(buffer, offset, count);
lock (_sync)
{
while (_readHead == _readTail && !_disposed)
@@ -835,6 +840,11 @@ namespace Renci.SshNet
/// <inheritdoc/>
public override void Write(byte[] buffer, int offset, int count)
{
#if !NET
ThrowHelper.
#endif
ValidateBufferArguments(buffer, offset, count);
ThrowHelper.ThrowObjectDisposedIf(_disposed, this);
while (count > 0)
@@ -3,7 +3,6 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes.Common
{
@@ -41,8 +40,6 @@ namespace Renci.SshNet.Tests.Classes.Common
{
Assert.IsNull(ex.InnerException);
ArgumentExceptionAssert.MessageEquals("Cannot be less than zero.", ex);
Assert.AreEqual("indentLevel", ex.ParamName);
}
}