diff options
author | Bob Ippolito <bob@redivi.com> | 2023-04-04 10:59:13 -0700 |
---|---|---|
committer | Bob Ippolito <bob@redivi.com> | 2023-04-04 10:59:13 -0700 |
commit | 59dac4e82cd6766fc31a9389d573d732580eaab5 (patch) | |
tree | 2cba0cbde6419fa11c6111d82f64b989c46455ec | |
parent | 1e495c1199f56c2e8e7931f20bda7481842e18ff (diff) | |
download | simplejson-59dac4e82cd6766fc31a9389d573d732580eaab5.tar.gz |
SJ-PT-23-03: Backport integer string length limitation to limit quadratic parsing
-rw-r--r-- | CHANGES.txt | 2 | ||||
-rw-r--r-- | index.rst | 14 | ||||
-rw-r--r-- | simplejson/__init__.py | 4 | ||||
-rw-r--r-- | simplejson/decoder.py | 15 | ||||
-rw-r--r-- | simplejson/tests/test_decode.py | 8 |
5 files changed, 40 insertions, 3 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index ddb2bd8..b70200f 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,6 +4,8 @@ Version 3.19.0 released 2023-04-XX implementation of the decoder (SJ-PT-23-01) * Fix missing reference count decrease if PyOS_string_to_double raises an exception in Python 2.x; was probably unreachable (SJ-PT-23-02) +* Backport the integer string length limitation from Python 3.11 to + limit quadratic number parsing (SJ-PT-23-03) Version 3.18.4 released 2023-03-14 @@ -412,6 +412,13 @@ Basic Usage be used to use another datatype or parser for JSON integers (e.g. :class:`float`). + .. versionchanged:: 3.19.0 + The integer to string conversion length limitation introduced in + Python 3.11 has been backported. An attempt to parse an integer + with more than 4300 digits will result in an exception unless a + suitable alternative parser is specified + (e.g. :class:`decimal.Decimal`) + *parse_constant*, if specified, will be called with one of the following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This can be used to raise an exception if invalid JSON numbers are encountered. @@ -502,6 +509,13 @@ Encoders and decoders be used to use another datatype or parser for JSON integers (e.g. :class:`float`). + .. versionchanged:: 3.19.0 + The integer to string conversion length limitation introduced in + Python 3.11 has been backported. An attempt to parse an integer + with more than 4300 digits will result in an exception unless a + suitable alternative parser is specified + (e.g. :class:`decimal.Decimal`) + *parse_constant*, if specified, will be called with one of the following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This can be used to raise an exception if invalid JSON numbers are encountered. diff --git a/simplejson/__init__.py b/simplejson/__init__.py index 2f0bebf..92b6009 100644 --- a/simplejson/__init__.py +++ b/simplejson/__init__.py @@ -442,12 +442,12 @@ def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, takes priority. *parse_float*, if specified, will be called with the string of every - JSON float to be decoded. By default, this is equivalent to + JSON float to be decoded. By default, this is equivalent to ``float(num_str)``. This can be used to use another datatype or parser for JSON floats (e.g. :class:`decimal.Decimal`). *parse_int*, if specified, will be called with the string of every - JSON int to be decoded. By default, this is equivalent to + JSON int to be decoded. By default, this is equivalent to ``int(num_str)``. This can be used to use another datatype or parser for JSON integers (e.g. :class:`float`). diff --git a/simplejson/decoder.py b/simplejson/decoder.py index e1f10ae..c28e445 100644 --- a/simplejson/decoder.py +++ b/simplejson/decoder.py @@ -46,6 +46,19 @@ BACKSLASH = { DEFAULT_ENCODING = "utf-8" +if hasattr(sys, 'get_int_max_str_digits'): + bounded_int = int +else: + def bounded_int(s, INT_MAX_STR_DIGITS=4300): + """Backport of the integer string length conversion limitation + + https://docs.python.org/3/library/stdtypes.html#int-max-str-digits + """ + if len(s) > INT_MAX_STR_DIGITS: + raise ValueError("Exceeds the limit (%s) for integer string conversion: value has %s digits" % (INT_MAX_STR_DIGITS, len(s))) + return int(s) + + def scan_four_digit_hex(s, end, _m=re.compile(r'^[0-9a-fA-F]{4}$').match): """Scan a four digit hex number from s[end:end + 4] """ @@ -349,7 +362,7 @@ class JSONDecoder(object): self.object_hook = object_hook self.object_pairs_hook = object_pairs_hook self.parse_float = parse_float or float - self.parse_int = parse_int or int + self.parse_int = parse_int or bounded_int self.parse_constant = parse_constant or _CONSTANTS.__getitem__ self.strict = strict self.parse_object = JSONObject diff --git a/simplejson/tests/test_decode.py b/simplejson/tests/test_decode.py index 6960ee5..317b4f9 100644 --- a/simplejson/tests/test_decode.py +++ b/simplejson/tests/test_decode.py @@ -2,6 +2,7 @@ from __future__ import absolute_import import decimal from unittest import TestCase +import sys import simplejson as json from simplejson.compat import StringIO, b, binary_type from simplejson import OrderedDict @@ -117,3 +118,10 @@ class TestDecode(TestCase): diff = id(x) - id(y) self.assertRaises(ValueError, j.scan_once, y, diff) self.assertRaises(ValueError, j.raw_decode, y, i) + + def test_bounded_int(self): + # SJ-PT-23-03, limit quadratic number parsing per Python 3.11 + max_str_digits = getattr(sys, 'get_int_max_str_digits', lambda: 4300)() + s = '1' + '0' * (max_str_digits - 1) + self.assertEqual(json.loads(s), int(s)) + self.assertRaises(ValueError, json.loads, s + '0') |