Skip to content

Commit

Permalink
[release/9.0] Fix length check for Convert.TryToHexString{Lower} (#11…
Browse files Browse the repository at this point in the history
…0228)

* Fix length check for Convert.TryToHexString{Lower}

The size of destination should not be less than double source's length.

Fix #109807

* Use stackalloc to create a Span

* Use new char[] to instead potentially unbounded stackalloc

---------

Co-authored-by: Universorum <[email protected]>
  • Loading branch information
github-actions[bot] and universorum authored Dec 3, 2024
1 parent f6615d2 commit 9da8c6a
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 4 deletions.
4 changes: 2 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/Convert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3099,7 +3099,7 @@ public static bool TryToHexString(ReadOnlySpan<byte> source, Span<char> destinat
charsWritten = 0;
return true;
}
else if (source.Length > int.MaxValue / 2 || destination.Length > source.Length * 2)
else if (source.Length > int.MaxValue / 2 || destination.Length < source.Length * 2)
{
charsWritten = 0;
return false;
Expand Down Expand Up @@ -3176,7 +3176,7 @@ public static bool TryToHexStringLower(ReadOnlySpan<byte> source, Span<char> des
charsWritten = 0;
return true;
}
else if (source.Length > int.MaxValue / 2 || destination.Length > source.Length * 2)
else if (source.Length > int.MaxValue / 2 || destination.Length < source.Length * 2)
{
charsWritten = 0;
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,23 @@ public static void KnownByteSequence()
{
byte[] inputBytes = new byte[] { 0x00, 0x01, 0x02, 0xFD, 0xFE, 0xFF };
Assert.Equal("000102FDFEFF", Convert.ToHexString(inputBytes));

Span<char> output = stackalloc char[12];
Assert.True(Convert.TryToHexString(inputBytes, output, out int charsWritten));
Assert.Equal(12, charsWritten);
Assert.Equal("000102FDFEFF", output.ToString());
}

[Fact]
public static void KnownByteSequenceLower()
{
byte[] inputBytes = new byte[] { 0x00, 0x01, 0x02, 0xFD, 0xFE, 0xFF };
Assert.Equal("000102fdfeff", Convert.ToHexStringLower(inputBytes));

Span<char> output = stackalloc char[12];
Assert.True(Convert.TryToHexStringLower(inputBytes, output, out int charsWritten));
Assert.Equal(12, charsWritten);
Assert.Equal("000102fdfeff", output.ToString());
}

[Fact]
Expand All @@ -34,7 +44,13 @@ public static void CompleteValueRange()
sb.Append($"{i:X2}");
}

Assert.Equal(sb.ToString(), Convert.ToHexString(values));
string excepted = sb.ToString();
Assert.Equal(excepted, Convert.ToHexString(values));

Span<char> output = stackalloc char[512];
Assert.True(Convert.TryToHexString(values, output, out int charsWritten));
Assert.Equal(512, charsWritten);
Assert.Equal(excepted, output.ToString());
}

[Fact]
Expand All @@ -48,7 +64,13 @@ public static void CompleteValueRangeLower()
sb.Append($"{i:x2}");
}

Assert.Equal(sb.ToString(), Convert.ToHexStringLower(values));
string excepted = sb.ToString();
Assert.Equal(excepted, Convert.ToHexStringLower(values));

Span<char> output = stackalloc char[512];
Assert.True(Convert.TryToHexStringLower(values, output, out int charsWritten));
Assert.Equal(512, charsWritten);
Assert.Equal(excepted, output.ToString());
}

[Fact]
Expand All @@ -57,6 +79,13 @@ public static void ZeroLength()
byte[] inputBytes = Convert.FromHexString("000102FDFEFF");
Assert.Same(string.Empty, Convert.ToHexString(inputBytes, 0, 0));
Assert.Same(string.Empty, Convert.ToHexStringLower(inputBytes, 0, 0));

int charsWritten;
Span<char> output = stackalloc char[12];
Assert.True(Convert.TryToHexString(default, output, out charsWritten));
Assert.Equal(0, charsWritten);
Assert.True(Convert.TryToHexStringLower(default, output, out charsWritten));
Assert.Equal(0, charsWritten);
}

[Fact]
Expand All @@ -68,6 +97,22 @@ public static void InvalidInputBuffer()
AssertExtensions.Throws<ArgumentNullException>("inArray", () => Convert.ToHexStringLower(null, 0, 0));
}

[Fact]
public static void InvalidOutputBuffer()
{
byte[] inputBytes = new byte[] { 0x00, 0x01, 0x02, 0xFD, 0xFE, 0xFF };
int charsWritten;
Span<char> output = stackalloc char[11];
Assert.False(Convert.TryToHexString(inputBytes, default, out charsWritten));
Assert.Equal(0, charsWritten);
Assert.False(Convert.TryToHexString(inputBytes, output, out charsWritten));
Assert.Equal(0, charsWritten);
Assert.False(Convert.TryToHexStringLower(inputBytes, default, out charsWritten));
Assert.Equal(0, charsWritten);
Assert.False(Convert.TryToHexStringLower(inputBytes, output, out charsWritten));
Assert.Equal(0, charsWritten);
}

[Fact]
public static void InvalidOffset()
{
Expand Down Expand Up @@ -95,6 +140,13 @@ public static unsafe void InputTooLarge()
{
AssertExtensions.Throws<ArgumentOutOfRangeException>("bytes", () => Convert.ToHexString(new ReadOnlySpan<byte>((void*)0, Int32.MaxValue)));
AssertExtensions.Throws<ArgumentOutOfRangeException>("bytes", () => Convert.ToHexStringLower(new ReadOnlySpan<byte>((void*)0, Int32.MaxValue)));

int charsWritten;
Span<char> output = new Span<char>((void*)0, Int32.MaxValue);
Assert.False(Convert.TryToHexString(new ReadOnlySpan<byte>((void*)0, Int32.MaxValue), output, out charsWritten));
Assert.Equal(0, charsWritten);
Assert.False(Convert.TryToHexStringLower(new ReadOnlySpan<byte>((void*)0, Int32.MaxValue), output, out charsWritten));
Assert.Equal(0, charsWritten);
}

public static IEnumerable<object[]> ToHexStringTestData()
Expand Down Expand Up @@ -137,12 +189,33 @@ public static unsafe void ToHexString(byte[] input, string expected)
Assert.Equal(expected, actual);
}

[Theory]
[MemberData(nameof(ToHexStringTestData))]
public static unsafe void TryToHexString(byte[] input, string expected)
{
Span<char> output = new char[expected.Length];
Assert.True(Convert.TryToHexString(input, output, out int charsWritten));
Assert.Equal(expected.Length, charsWritten);
Assert.Equal(expected, output.ToString());
}


[Theory]
[MemberData(nameof(ToHexStringTestData))]
public static unsafe void ToHexStringLower(byte[] input, string expected)
{
string actual = Convert.ToHexStringLower(input);
Assert.Equal(expected.ToLower(), actual);
}

[Theory]
[MemberData(nameof(ToHexStringTestData))]
public static unsafe void TryToHexStringLower(byte[] input, string expected)
{
Span<char> output = new char[expected.Length];
Assert.True(Convert.TryToHexStringLower(input, output, out int charsWritten));
Assert.Equal(expected.Length, charsWritten);
Assert.Equal(expected.ToLower(), output.ToString());
}
}
}

0 comments on commit 9da8c6a

Please sign in to comment.