From 0fbb6a154422f191325d2d9634c217c0873e5fa8 Mon Sep 17 00:00:00 2001 From: Oleg Golberg Date: Thu, 4 Jun 2026 11:50:27 -0400 Subject: [PATCH 1/2] Fix: peekNumber rejects some numerals like 2^64 + "0" Issue: the "leading zero" logic in peekNumber, which tries to reject octal representations, does not account for long overflows. This results in valid numeric literals like "184467440737095516160" (2^64 + "0") being rejected in STRICT parsing mode. The easiest way to reproduce this is to serialize and deserialize a BigInteger with the value above. This is a minimal fix which adds an overflow check to the leading zero condition. --- .../java/com/google/gson/stream/JsonReader.java | 2 +- .../java/com/google/gson/stream/JsonReaderTest.java | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/gson/src/main/java/com/google/gson/stream/JsonReader.java b/gson/src/main/java/com/google/gson/stream/JsonReader.java index eaed974527..8a15271df6 100644 --- a/gson/src/main/java/com/google/gson/stream/JsonReader.java +++ b/gson/src/main/java/com/google/gson/stream/JsonReader.java @@ -853,7 +853,7 @@ private int peekNumber() throws IOException { value = -(c - '0'); last = NUMBER_CHAR_DIGIT; } else if (last == NUMBER_CHAR_DIGIT) { - if (value == 0) { + if (fitsInLong && value == 0) { return PEEKED_NONE; // Leading '0' prefix is not allowed (since it could be octal). } long newValue = value * 10 - (c - '0'); diff --git a/gson/src/test/java/com/google/gson/stream/JsonReaderTest.java b/gson/src/test/java/com/google/gson/stream/JsonReaderTest.java index e7916ecf37..4ce0345afa 100644 --- a/gson/src/test/java/com/google/gson/stream/JsonReaderTest.java +++ b/gson/src/test/java/com/google/gson/stream/JsonReaderTest.java @@ -820,6 +820,19 @@ public void testNumberWithOctalPrefix() throws IOException { assertStrictError(e, expectedLocation); } + /** + * Regression test for a bug where {@code peekNumber} rejected a valid numeric literal whose + * prefix happened to be a multiple of 264. The {@code long} accumulator wraps to + * exactly zero in that case, which the old "leading zero" guard misread as an octal prefix. + */ + @Test + public void testNumberLongAccumulatorOverflowsToZero() throws IOException { + String number = "184467440737095516160"; + JsonReader reader = new JsonReader(reader(number)); + assertThat(reader.peek()).isEqualTo(NUMBER); + assertThat(reader.nextString()).isEqualTo(number); + } + @Test public void testBooleans() throws IOException { JsonReader reader = new JsonReader(reader("[true,false]")); From 0de921d21af0090756444f03659ec22c94b987c1 Mon Sep 17 00:00:00 2001 From: Oleg Golberg Date: Thu, 4 Jun 2026 12:03:05 -0400 Subject: [PATCH 2/2] strict --- gson/src/test/java/com/google/gson/stream/JsonReaderTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/gson/src/test/java/com/google/gson/stream/JsonReaderTest.java b/gson/src/test/java/com/google/gson/stream/JsonReaderTest.java index 4ce0345afa..e8d546b577 100644 --- a/gson/src/test/java/com/google/gson/stream/JsonReaderTest.java +++ b/gson/src/test/java/com/google/gson/stream/JsonReaderTest.java @@ -829,6 +829,7 @@ public void testNumberWithOctalPrefix() throws IOException { public void testNumberLongAccumulatorOverflowsToZero() throws IOException { String number = "184467440737095516160"; JsonReader reader = new JsonReader(reader(number)); + reader.setStrictness(Strictness.STRICT); assertThat(reader.peek()).isEqualTo(NUMBER); assertThat(reader.nextString()).isEqualTo(number); }