Skip to content

Commit

Permalink
Convert.FromHexString exception with too large buffer (#105426)
Browse files Browse the repository at this point in the history
* Fix destination slicing

* Correct destination slice

* correct test expected value

* Apply suggestions and add more unit tests.

---------

Co-authored-by: Eirik Tsarpalis <eirik.tsarpalis@gmail.com>
  • Loading branch information
hrrrrustic and eiriktsarpalis authored Aug 12, 2024
1 parent 58d6c58 commit 69bb1a4
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 5 deletions.
18 changes: 13 additions & 5 deletions src/libraries/System.Private.CoreLib/src/System/Convert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2999,19 +2999,27 @@ public static OperationStatus FromHexString(ReadOnlySpan<char> source, Span<byte
return remainder == 1 ? OperationStatus.NeedMoreData : OperationStatus.Done;
}

var result = OperationStatus.Done;
OperationStatus result;

if (destination.Length < quotient)
{
source = source.Slice(0, destination.Length * 2);
quotient = destination.Length;
result = OperationStatus.DestinationTooSmall;
}
else if (remainder == 1)
else
{
source = source.Slice(0, source.Length - 1);
destination = destination.Slice(0, destination.Length - 1);
result = OperationStatus.NeedMoreData;
if (remainder == 1)
{
source = source.Slice(0, source.Length - 1);
result = OperationStatus.NeedMoreData;
}
else
{
result = OperationStatus.Done;
}

destination = destination.Slice(0, quotient);
}

if (!HexConverter.TryDecodeFromUtf16(source, destination, out charsConsumed))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,42 @@ public static void TooShortDestination()
Assert.Equal(destinationSize, bytesWritten);
}

[Fact]
public static void TooLongDestination()
{
string hex = Convert.ToHexString([255, 255, 255]);
byte[] buffer = new byte[100];
var status = Convert.FromHexString(hex, buffer, out int charsConsumed, out int bytesWritten);

Assert.Equal(OperationStatus.Done, status);
Assert.Equal(hex.Length, charsConsumed);
Assert.Equal(hex.Length / 2, bytesWritten);
}

[Fact]
public static void ExactDestination()
{
string hex = "ffffff";
byte[] buffer = new byte[3];
var status = Convert.FromHexString(hex, buffer, out int charsConsumed, out int bytesWritten);

Assert.Equal(OperationStatus.Done, status);
Assert.Equal(hex.Length, charsConsumed);
Assert.Equal(hex.Length / 2, bytesWritten);
}

[Fact]
public static void ExactDestination_TrailingCharacter()
{
string hex = "fffff";
byte[] buffer = new byte[2];
var status = Convert.FromHexString(hex, buffer, out int charsConsumed, out int bytesWritten);

Assert.Equal(OperationStatus.NeedMoreData, status);
Assert.Equal(hex.Length - 1, charsConsumed);
Assert.Equal(hex.Length / 2, bytesWritten);
}

[Fact]
public static void NeedMoreData_OrFormatException()
{
Expand All @@ -152,6 +188,7 @@ public static void NeedMoreData_OrFormatException()
Assert.Equal(0, consumed);
Assert.Equal(0, written);

// Odd length
spanHex = hex.AsSpan(0, hex.Length - 1);

var oneOffResult = Convert.FromHexString(spanHex, destination, out consumed, out written);
Expand All @@ -160,6 +197,15 @@ public static void NeedMoreData_OrFormatException()
Assert.Equal(OperationStatus.NeedMoreData, oneOffResult);
Assert.Equal(spanHex.Length - 1, consumed);
Assert.Equal((spanHex.Length - 1) / 2, written);

// Even length
spanHex = hex.AsSpan(0, hex.Length - 2);

var twoOffResult = Convert.FromHexString(spanHex, destination, out consumed, out written);

Assert.Equal(OperationStatus.Done, twoOffResult);
Assert.Equal(spanHex.Length, consumed);
Assert.Equal(spanHex.Length / 2, written);
}
}
}

0 comments on commit 69bb1a4

Please sign in to comment.