From f722174ea1975aabd2d4709cb942b0d2aa537f48 Mon Sep 17 00:00:00 2001 From: Oleg Golberg Date: Thu, 4 Jun 2026 14:32:16 -0400 Subject: [PATCH] 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. This bug was inherited from Gson, see https://github.com/google/gson/pull/3034. --- .../main/java/com/squareup/moshi/-JsonUtf8Reader.kt | 2 +- .../java/com/squareup/moshi/JsonUtf8ReaderTest.java | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/moshi/src/main/java/com/squareup/moshi/-JsonUtf8Reader.kt b/moshi/src/main/java/com/squareup/moshi/-JsonUtf8Reader.kt index adea13fc1..4cfc34348 100644 --- a/moshi/src/main/java/com/squareup/moshi/-JsonUtf8Reader.kt +++ b/moshi/src/main/java/com/squareup/moshi/-JsonUtf8Reader.kt @@ -468,7 +468,7 @@ internal class `-JsonUtf8Reader` : JsonReader { } NUMBER_CHAR_DIGIT -> { - if (value == 0L) { + if (fitsInLong && value == 0L) { return PEEKED_NONE // Leading '0' prefix is not allowed (since it could be octal). } val newValue = value * 10 - (c - '0').toLong() diff --git a/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java b/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java index 551f3b73a..d7450a6f9 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java @@ -362,6 +362,19 @@ public void negativeZeroIsANumber() throws Exception { assertEquals("-0", reader.nextString()); } + /** + * 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 numberLongAccumulatorOverflowsToZero() throws IOException { + String number = "184467440737095516160"; + JsonReader reader = newReader(number); + assertThat(reader.peek()).isEqualTo(NUMBER); + assertThat(reader.nextString()).isEqualTo(number); + } + @Test public void numberToStringCoersion() throws Exception { JsonReader reader = newReader("[0, 9223372036854775807, 2.5, 3.010, \"a\", \"5\"]");