Skip to content

Commit e3c6605

Browse files
Fix a couple error cases in Json parsing (#116446)
1 parent e7c1960 commit e3c6605

File tree

5 files changed

+58
-3
lines changed

5 files changed

+58
-3
lines changed

src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.MultiSegment.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ private bool CheckLiteralMultiSegment(ReadOnlySpan<byte> span, ReadOnlySpan<byte
548548
{
549549
_bytePositionInLine += FindMismatch(span, literal);
550550

551-
int amountToWrite = Math.Min(span.Length, (int)_bytePositionInLine + 1);
551+
int amountToWrite = AmountToWrite(span, _bytePositionInLine, readSoFar, written);
552552
span.Slice(0, amountToWrite).CopyTo(readSoFar);
553553
written += amountToWrite;
554554
goto Throw;
@@ -558,7 +558,7 @@ private bool CheckLiteralMultiSegment(ReadOnlySpan<byte> span, ReadOnlySpan<byte
558558
if (!literal.StartsWith(span))
559559
{
560560
_bytePositionInLine += FindMismatch(span, literal);
561-
int amountToWrite = Math.Min(span.Length, (int)_bytePositionInLine + 1);
561+
int amountToWrite = AmountToWrite(span, _bytePositionInLine, readSoFar, written);
562562
span.Slice(0, amountToWrite).CopyTo(readSoFar);
563563
written += amountToWrite;
564564
goto Throw;
@@ -605,7 +605,7 @@ private bool CheckLiteralMultiSegment(ReadOnlySpan<byte> span, ReadOnlySpan<byte
605605
{
606606
_bytePositionInLine += FindMismatch(span, leftToMatch);
607607

608-
amountToWrite = Math.Min(span.Length, (int)_bytePositionInLine + 1);
608+
amountToWrite = AmountToWrite(span, _bytePositionInLine, readSoFar, written);
609609
span.Slice(0, amountToWrite).CopyTo(readSoFar.Slice(written));
610610
written += amountToWrite;
611611

@@ -616,6 +616,13 @@ private bool CheckLiteralMultiSegment(ReadOnlySpan<byte> span, ReadOnlySpan<byte
616616
alreadyMatched = span.Length;
617617
}
618618
}
619+
620+
static int AmountToWrite(ReadOnlySpan<byte> span, long bytePositionInLine, ReadOnlySpan<byte> readSoFar, int written)
621+
{
622+
return Math.Min(
623+
readSoFar.Length - written,
624+
Math.Min(span.Length, (int)bytePositionInLine + 1));
625+
}
619626
Throw:
620627
_totalConsumed = prevTotalConsumed;
621628
consumed = default;

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/DateOnlyConverter.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ private static DateOnly ReadCore(ref Utf8JsonReader reader)
4444
{
4545
Span<byte> stackSpan = stackalloc byte[MaxEscapedFormatLength];
4646
int bytesWritten = reader.CopyString(stackSpan);
47+
48+
// CopyString can unescape which can change the length, so we need to perform the length check again.
49+
if (bytesWritten < FormatLength)
50+
{
51+
ThrowHelper.ThrowFormatException(DataType.DateOnly);
52+
}
53+
4754
source = stackSpan.Slice(0, bytesWritten);
4855
}
4956

src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonTestHelper.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Diagnostics.CodeAnalysis;
88
using System.Globalization;
99
using System.IO;
10+
using System.Linq;
1011
using System.Text.Json.Tests;
1112
using System.Text.RegularExpressions;
1213
using Newtonsoft.Json;
@@ -229,6 +230,11 @@ public static List<ReadOnlySequence<byte>> GetSequences(ReadOnlyMemory<byte> dat
229230
return sequences;
230231
}
231232

233+
public static ReadOnlySequence<byte> GetSequence(IEnumerable<byte[]> json)
234+
{
235+
return BufferFactory.Create(json.ToArray());
236+
}
237+
232238
internal static ReadOnlySequence<byte> SegmentInto(ReadOnlyMemory<byte> data, int segmentCount)
233239
{
234240
if (segmentCount < 2)

src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,7 @@ public static void DateOnly_Read_Nullable_Tests()
650650
[InlineData("[]", false)]
651651
[InlineData("true", false)]
652652
[InlineData("null", false)]
653+
[InlineData("05-1\\u0000", true)] // String length 10 before unescaping, less than 10 after escaping
653654
public static void DateOnly_Read_Failure(string json, bool addQuotes = true)
654655
{
655656
if (addQuotes)

src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.MultiSegment.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,6 +1633,40 @@ public static void ReadJsonTokenWithExtraValueMultiSegment(string jsonString)
16331633
}
16341634
}
16351635

1636+
[Fact]
1637+
public static void MultiSegmentInvalidLiteral()
1638+
{
1639+
// Tests edge case in Utf8JsonReader.CheckLiteralMultiSegment error handling
1640+
// when segment has invalid literal and more characters than stack-allocated span (5)
1641+
IEnumerable<byte[]> bytes = ["tr"u8.ToArray(), "uabcdef"u8.ToArray()];
1642+
ReadOnlySequence<byte> sequence = JsonTestHelper.GetSequence(bytes);
1643+
1644+
Utf8JsonReader reader = new Utf8JsonReader(sequence, isFinalBlock: true, state: default);
1645+
1646+
JsonTestHelper.AssertThrows<JsonException>(ref reader, (ref reader) =>
1647+
{
1648+
reader.Read();
1649+
});
1650+
}
1651+
1652+
[Fact]
1653+
public static void MultiSegmentInvalidLiteralInObject()
1654+
{
1655+
// Tests edge case in Utf8JsonReader.CheckLiteralMultiSegment error handling
1656+
// when segment has invalid literal after having done some prior reads (i.e. start of object and property name)
1657+
IEnumerable<byte[]> bytes = ["{\"foo\""u8.ToArray(), ":nul234"u8.ToArray()];
1658+
ReadOnlySequence<byte> sequence = JsonTestHelper.GetSequence(bytes);
1659+
1660+
Utf8JsonReader reader = new Utf8JsonReader(sequence, isFinalBlock: true, state: default);
1661+
Assert.True(reader.Read()); // StartObject
1662+
Assert.True(reader.Read()); // PropertyName
1663+
1664+
JsonTestHelper.AssertThrows<JsonException>(ref reader, (ref reader) =>
1665+
{
1666+
reader.Read();
1667+
});
1668+
}
1669+
16361670
[Theory]
16371671
[MemberData(nameof(JsonTokenWithExtraValueAndComments))]
16381672
public static void ReadJsonTokenWithExtraValueAndCommentsMultiSegment(string jsonString)

0 commit comments

Comments
 (0)