Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert.FromHexString exception with too large buffer #105426

Merged
merged 8 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src/libraries/System.Private.CoreLib/src/System/Convert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3007,11 +3007,15 @@ public static OperationStatus FromHexString(ReadOnlySpan<char> source, Span<byte
quotient = destination.Length;
result = OperationStatus.DestinationTooSmall;
}
else if (remainder == 1)
else if (destination.Length > quotient)
Copy link
Member

@eiriktsarpalis eiriktsarpalis Aug 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we also be handling remainders in cases where the destination buffer precisely matches the quotient?

Suggested change
else if (destination.Length > quotient)
else

Are we missing a unit test for that case?

{
source = source.Slice(0, source.Length - 1);
destination = destination.Slice(0, destination.Length - 1);
if (remainder == 1)
{
source = source.Slice(0, source.Length - 1);
}

result = OperationStatus.NeedMoreData;
Copy link
Member

@eiriktsarpalis eiriktsarpalis Aug 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the destination buffer can fit the result and the remainder is 0, why should the status be NeedMoreData? Do we have unit test for that case?

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,18 @@ 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.NeedMoreData, status);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that this assertion is incorrect. NeedMoreData should only be returned if the parser handled partial data (i.e. there's an odd number of hex chars). If the buffer fits the result it should always return Done.

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

[Fact]
public static void NeedMoreData_OrFormatException()
{
Expand All @@ -152,6 +164,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 +173,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.NeedMoreData, twoOffResult);
Assert.Equal(spanHex.Length, consumed);
Assert.Equal(spanHex.Length / 2, written);
}
}
}
Loading