diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index 40d2d6afc..1b647146f 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -278,7 +278,7 @@ class json_sax_dom_parser if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); + return parse_error(0, "", out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); } return true; @@ -327,7 +327,7 @@ class json_sax_dom_parser if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + return parse_error(0, "", out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); } if (len != detail::unknown_size()) @@ -611,7 +611,7 @@ class json_sax_dom_callback_parser // check object limit if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); + return parse_error(0, "", out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); } } return true; @@ -730,7 +730,7 @@ class json_sax_dom_callback_parser // check array limit if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + return parse_error(0, "", out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); } if (len != detail::unknown_size()) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index efc8e3b94..624768cbd 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -10992,7 +10992,7 @@ class json_sax_dom_parser if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); + return parse_error(0, "", out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); } return true; @@ -11041,7 +11041,7 @@ class json_sax_dom_parser if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + return parse_error(0, "", out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); } if (len != detail::unknown_size()) @@ -11325,7 +11325,7 @@ class json_sax_dom_callback_parser // check object limit if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); + return parse_error(0, "", out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); } } return true; @@ -11444,7 +11444,7 @@ class json_sax_dom_callback_parser // check array limit if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + return parse_error(0, "", out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); } if (len != detail::unknown_size()) diff --git a/tests/src/unit-regression2.cpp b/tests/src/unit-regression2.cpp index 4280ec361..82b4ac07c 100644 --- a/tests/src/unit-regression2.cpp +++ b/tests/src/unit-regression2.cpp @@ -763,4 +763,30 @@ TEST_CASE("regression tests 2") } +TEST_CASE("regression test - excessive binary container size honors allow_exceptions=false") +{ + // CBOR array with declared length 2^63 + const std::vector cbor = {0x9b, 0x80, 0, 0, 0, 0, 0, 0, 0}; + // CBOR map with declared length 2^63 + const std::vector cbor_m = {0xbb, 0x80, 0, 0, 0, 0, 0, 0, 0}; + // UBJSON array with declared length 2^63-1 + const std::vector ubj = {'[', '#', 'L', 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + // BJData array with declared length 2^63-1 (little endian) + const std::vector bjd = {'[', '#', 'L', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}; + + // allow_exceptions=false must report failure instead of throwing/aborting + CHECK(json::from_cbor(cbor, true, false).is_discarded()); + CHECK(json::from_cbor(cbor_m, true, false).is_discarded()); + CHECK(json::from_ubjson(ubj, true, false).is_discarded()); + CHECK(json::from_bjdata(bjd, true, false).is_discarded()); + + // allow_exceptions=true (the default) must still throw exactly as before + CHECK_THROWS_AS(json::from_cbor(cbor), json::out_of_range); + CHECK_THROWS_WITH(json::from_cbor(cbor), + "[json.exception.out_of_range.408] excessive array size: 9223372036854775808"); + + // regression guard: a genuinely truncated CBOR input must remain discarded + CHECK(json::from_cbor(std::vector {0x9b, 0, 0, 0, 0, 0, 0, 0, 0x02}, true, false).is_discarded()); +} + DOCTEST_CLANG_SUPPRESS_WARNING_POP