This is an automated email from the ASF dual-hosted git repository.
markt-asf pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push:
new 221d759137 Review "Parse exponent-only numbers in the JSON parser"
221d759137 is described below
commit 221d7591378bc50f6eebbb172e75b8386d7f69c0
Author: Mark Thomas <[email protected]>
AuthorDate: Tue Nov 3 14:51:15 2026 +0000
Review "Parse exponent-only numbers in the JSON parser"
Describe behaviour change in changelog
Treat out of range number as a ParseException
---
java/org/apache/tomcat/util/json/JSONParser.java | 12 ++++--
java/org/apache/tomcat/util/json/JSONParser.jjt | 8 +++-
.../apache/tomcat/util/json/TestJSONParser.java | 48 ++++++++++++++++++++++
webapps/docs/changelog.xml | 17 ++++++++
4 files changed, 81 insertions(+), 4 deletions(-)
diff --git a/java/org/apache/tomcat/util/json/JSONParser.java
b/java/org/apache/tomcat/util/json/JSONParser.java
index 534692eb20..7abfab60a4 100644
--- a/java/org/apache/tomcat/util/json/JSONParser.java
+++ b/java/org/apache/tomcat/util/json/JSONParser.java
@@ -448,10 +448,16 @@ public class JSONParser implements JSONParserConstants {
}
}
} else {
- {
- if ("" != null) {
- return new java.math.BigDecimal(t.image);
+ try {
+ {
+ if ("" != null) {
+ return new java.math.BigDecimal(t.image);
+ }
}
+ } catch (NumberFormatException nfe) {
+ // The grammar admits exponents that BigDecimal can't
represent. Report them as a parse
+ // error rather than letting an unchecked exception
escape the parser.
+ throw new ParseException("Exponent out of range in
number [" + t.image + "]");
}
}
break;
diff --git a/java/org/apache/tomcat/util/json/JSONParser.jjt
b/java/org/apache/tomcat/util/json/JSONParser.jjt
index c50f41935a..89c05f3ae8 100644
--- a/java/org/apache/tomcat/util/json/JSONParser.jjt
+++ b/java/org/apache/tomcat/util/json/JSONParser.jjt
@@ -413,7 +413,13 @@ Number number(): {
if (nativeNumbers) {
return Double.valueOf(t.image);
} else {
- return new java.math.BigDecimal(t.image);
+ try {
+ return new java.math.BigDecimal(t.image);
+ } catch (NumberFormatException nfe) {
+ // The grammar admits exponents that BigDecimal can't
represent. Report them as a parse error
+ // rather than letting an unchecked exception escape the
parser.
+ throw new ParseException("Exponent out of range in number
[" + t.image + "]");
+ }
}
}
) | (
diff --git a/test/org/apache/tomcat/util/json/TestJSONParser.java
b/test/org/apache/tomcat/util/json/TestJSONParser.java
index 9771bbf0bb..47f0588cb8 100644
--- a/test/org/apache/tomcat/util/json/TestJSONParser.java
+++ b/test/org/apache/tomcat/util/json/TestJSONParser.java
@@ -111,6 +111,54 @@ public class TestJSONParser {
Assert.assertEquals(BigInteger.ONE, result.get("1E+5"));
}
+ /*
+ * The exponent of a number must be one that BigDecimal can represent. A
larger exponent must be reported as a
+ * ParseException rather than as an unchecked NumberFormatException.
+ */
+ @Test
+ public void testExponentOutOfRangeIsParseException() {
+ for (String number : new String[] { "1e-2147483649", "1e2147483649",
"1.5e-2147483649", "-1E2147483649" }) {
+ try {
+ new JSONParser("[" + number + "]").parse();
+ Assert.fail("A ParseException was expected for " + number);
+ } catch (ParseException e) {
+ Assert.assertTrue(e.getMessage(),
e.getMessage().contains(number));
+ }
+ }
+ }
+
+ @Test
+ public void testExponentOutOfRangeAsKeyIsParseException() {
+ Assert.assertThrows(ParseException.class, () -> new
JSONParser("{1e2147483649:1}").parseObject());
+ }
+
+ @Test
+ public void testLargestExponentsAccepted() throws ParseException {
+ JSONParser parser = new JSONParser("[1e2147483647, 1e-2147483647]");
+ List<Object> values = parser.parseArray();
+ Assert.assertEquals(new BigDecimal("1e2147483647"), values.get(0));
+ Assert.assertEquals(new BigDecimal("1e-2147483647"), values.get(1));
+ }
+
+ @Test
+ public void testExponentWithLeadingZeros() throws ParseException {
+ Assert.assertEquals(new BigDecimal("1E5"), new
JSONParser("1e05").parse());
+ }
+
+ /*
+ * Bare words that start with a number but are not numbers are not
affected by the exponent-only number syntax.
+ */
+ @Test
+ public void testBareWordKeysStartingWithNumber() throws ParseException {
+ Map<String, Object> result = new JSONParser("{1e5x:1, 12abc:2, 1e:3,
3E2:4}").parseObject();
+ Assert.assertEquals(BigInteger.valueOf(1), result.get("1e5x"));
+ Assert.assertEquals(BigInteger.valueOf(2), result.get("12abc"));
+ Assert.assertEquals(BigInteger.valueOf(3), result.get("1e"));
+ // An exponent-only number is a number, so its key is the normalised
form of the number
+ Assert.assertEquals(BigInteger.valueOf(4), result.get("3E+2"));
+ Assert.assertEquals(4, result.size());
+ }
+
private static String nest(int depth) {
StringBuilder result = new StringBuilder(depth * 2);
for (int i = 0; i < depth; i++) {
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 7c0def85ae..27de6fa631 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -613,6 +613,23 @@
closes the entire connection. These frames are already permitted when
the stream is closed in the other direction. (remm)
</fix>
+ <fix>
+ The JSON parser now accepts numbers that have an exponent but no
+ fraction, such as <code>1e5</code>, as required by RFC 8259. Note that
+ when the lenient dialect is used, a bare object key that is such a
+ number (for example <code>{1e5:1}</code>) is now a number and the key
+ is the string form of the parsed number (<code>1E+5</code>) rather than
+ the original text, as already happened for bare keys that have both a
+ fraction and an exponent. Quoted keys are not affected. Numbers with an
+ exponent that is too large or too small to be represented are now
+ rejected with a <code>ParseException</code> rather than an unchecked
+ <code>NumberFormatException</code>. (remm)
+ </fix>
+ <fix>
+ With native numbers enabled, the JSON parser now returns integers that
+ do not fit in a <code>long</code> as <code>BigInteger</code> rather
than
+ failing with an unchecked <code>NumberFormatException</code>. (remm)
+ </fix>
<fix>
The JSON parser now rejects input with a nesting depth greater than
1000 with a <code>ParseException</code>. Previously, deeply nested
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]