Skip to content

Commit

Permalink
SJ-PT-23-03: Backport integer string length limitation to limit quadr…
Browse files Browse the repository at this point in the history
…atic parsing
  • Loading branch information
etrepum committed Apr 4, 2023
1 parent 1e495c1 commit 59dac4e
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGES.txt
Expand Up @@ -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

Expand Down
14 changes: 14 additions & 0 deletions index.rst
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions simplejson/__init__.py
Expand Up @@ -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`).
Expand Down
15 changes: 14 additions & 1 deletion simplejson/decoder.py
Expand Up @@ -46,6 +46,19 @@ def _floatconstants():

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]
"""
Expand Down Expand Up @@ -349,7 +362,7 @@ def __init__(self, encoding=None, object_hook=None, parse_float=None,
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
Expand Down
8 changes: 8 additions & 0 deletions simplejson/tests/test_decode.py
Expand Up @@ -2,6 +2,7 @@
import decimal
from unittest import TestCase

import sys
import simplejson as json
from simplejson.compat import StringIO, b, binary_type
from simplejson import OrderedDict
Expand Down Expand Up @@ -117,3 +118,10 @@ def test_bounds_checking(self):
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')

0 comments on commit 59dac4e

Please sign in to comment.