mirror of
https://github.com/nlohmann/json.git
synced 2026-10-04 13:40:33 +00:00
Fix value(json_pointer, default) aborting under JSON_NOEXCEPTION (#5700)
With exceptions disabled (JSON_NOEXCEPTION or -fno-exceptions),
value(const json_pointer&, default) called std::abort() for array
reference tokens that array_index() rejects with out_of_range.404/410:
indices too large to fit size_type, the empty token ("/"), and tokens
like "/1a". With exceptions enabled, the same tokens correctly yielded
the default value, because get_checked_or_null() relied on
JSON_TRY/JSON_INTERNAL_CATCH (detail::out_of_range&) to turn the
exception into nullptr; under JSON_NOEXCEPTION, JSON_THROW aborts
before that catch is ever reached.
get_checked_or_null() now detects those out-of-range tokens itself,
the same way contains(json_pointer) already does (#5495), and only
calls array_index() for tokens that must still raise parse_error.106
or parse_error.109 (e.g. "/01", "/+1"), matching the documented
behavior of value().
Added regression tests to tests/src/unit-disabled_exceptions.cpp
(built with JSON_NOEXCEPTION and -fno-exceptions) and the matching
checks to tests/src/unit-element_access2.cpp for normal exception
mode.
Fixes #5672.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
@@ -47,6 +47,21 @@ TEST_CASE("Tests with disabled exceptions")
|
||||
delete sax_no_exception::error_string; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
}
|
||||
|
||||
SECTION("issue #5672 - value(json_pointer, default) must not abort for array tokens that are not a valid index")
|
||||
{
|
||||
const json j = {1, 2, 3};
|
||||
|
||||
// a syntactically valid index that is out of range for this array
|
||||
CHECK(j.value("/7"_json_pointer, 42) == 42);
|
||||
// a reference token that is not a number at all
|
||||
CHECK(j.value("/1a"_json_pointer, 42) == 42);
|
||||
// the empty reference token (JSON pointer "/")
|
||||
CHECK(j.value("/"_json_pointer, 42) == 42);
|
||||
// an index whose magnitude does not fit into size_type
|
||||
CHECK(j.value("/99999999999999999999999"_json_pointer, 42) == 42);
|
||||
CHECK(j.value("/18446744073709551615"_json_pointer, 42) == 42);
|
||||
}
|
||||
|
||||
SECTION("growing an ordered_json object")
|
||||
{
|
||||
auto j = nlohmann::ordered_json::object();
|
||||
|
||||
@@ -516,6 +516,21 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j
|
||||
CHECK(j_array.value("/-"_json_pointer, 42) == 42);
|
||||
CHECK(j_array_const.value("/-"_json_pointer, 42) == 42);
|
||||
|
||||
// Test an index with a non-digit after a valid leading digit; this is
|
||||
// out_of_range (not parse_error) and must not throw (see #5672)
|
||||
CHECK(j_array.value("/1a"_json_pointer, 42) == 42);
|
||||
CHECK(j_array_const.value("/1a"_json_pointer, 42) == 42);
|
||||
|
||||
// Test the empty reference token (JSON pointer "/"); see #5672
|
||||
CHECK(j_array.value("/"_json_pointer, 42) == 42);
|
||||
CHECK(j_array_const.value("/"_json_pointer, 42) == 42);
|
||||
|
||||
// Test an index whose magnitude does not fit into size_type (see #5672)
|
||||
CHECK(j_array.value("/99999999999999999999999"_json_pointer, 42) == 42);
|
||||
CHECK(j_array_const.value("/99999999999999999999999"_json_pointer, 42) == 42);
|
||||
CHECK(j_array.value("/18446744073709551615"_json_pointer, 42) == 42);
|
||||
CHECK(j_array_const.value("/18446744073709551615"_json_pointer, 42) == 42);
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION)
|
||||
// Test malformed index (non-numeric) throws parse_error
|
||||
CHECK_THROWS_WITH_AS(j_array.value("/foo"_json_pointer, 1), "[json.exception.parse_error.109] parse error: array index 'foo' is not a number", typename Json::parse_error&);
|
||||
|
||||
Reference in New Issue
Block a user