diff --git a/crates/stdlib/src/json.rs b/crates/stdlib/src/json.rs index dc2fbbc8892..37691d2b926 100644 --- a/crates/stdlib/src/json.rs +++ b/crates/stdlib/src/json.rs @@ -9,12 +9,11 @@ mod _json { builtins::{PyBaseExceptionRef, PyStrRef, PyType}, convert::ToPyResult, function::{IntoFuncArgs, OptionalArg}, - protocol::PyIterReturn, + protocol::{handle_bytes_to_int_err, PyIterReturn}, types::{Callable, Constructor}, }; use core::str::FromStr; - use malachite_bigint::BigInt; - use rustpython_common::wtf8::Wtf8Buf; + use rustpython_common::{int::bytes_to_int, wtf8::Wtf8Buf}; use std::collections::HashMap; /// Skip JSON whitespace characters (space, tab, newline, carriage return). @@ -243,7 +242,12 @@ mod _json { } else if let Some(ref parse_int) = self.parse_int { parse_int.call((buf,), vm) } else { - Ok(vm.new_pyobj(BigInt::from_str(buf).unwrap())) + bytes_to_int(buf.as_bytes(), 10, vm.state.int_max_str_digits.load()) + .map(|value| vm.new_pyobj(value)) + .map_err(|e| { + let obj = vm.ctx.new_str(buf); + handle_bytes_to_int_err(e, obj.as_object(), vm) + }) }; Some((ret, buf.len())) } diff --git a/extra_tests/snippets/stdlib_json.py b/extra_tests/snippets/stdlib_json.py index e55382c8223..406476ae8c6 100644 --- a/extra_tests/snippets/stdlib_json.py +++ b/extra_tests/snippets/stdlib_json.py @@ -1,4 +1,5 @@ import json +import sys from io import BytesIO, StringIO from testutils import assert_raises @@ -261,3 +262,15 @@ def assert_no_native_stack_overflow(func): assert e.pos == 5, f"expected pos=5, got {e.pos}" else: raise AssertionError("expected JSONDecodeError") + +# Test that json.loads honors sys.int_max_str_digits +_min_limit = sys.int_info.str_digits_check_threshold +_orig_limit = sys.get_int_max_str_digits() +try: + sys.set_int_max_str_digits(_min_limit) + with assert_raises(ValueError): + json.loads("1" * (_min_limit + 1)) + assert json.loads("1" * _min_limit) == int("1" * _min_limit) + assert json.loads('42') == 42 +finally: + sys.set_int_max_str_digits(_orig_limit)