mirror of
https://github.com/sshnet/SSH.NET.git
synced 2026-09-10 09:15:47 +00:00
Add a Stream buffer validation helper (#1605)
* Add a Stream buffer validation helper * add ThrowHelper.ThrowIfNegative
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user