mirror of
https://github.com/nlohmann/json.git
synced 2026-09-06 00:08:00 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bb551f46f |
@@ -748,20 +748,6 @@ class json_pointer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// the reference token consists only of digits at this point (cf. checks
|
|
||||||
// above); however, its numeric value might not be representable, in which
|
|
||||||
// case array_index() would throw out_of_range.404/410 -- contains() must
|
|
||||||
// not throw (see #5395), so such a reference token is treated as "not found"
|
|
||||||
errno = 0; // strtoull() does not reset errno on success
|
|
||||||
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
|
||||||
const unsigned long long magnitude = std::strtoull(reference_token.c_str(), &p_end, 10); // NOLINT(runtime/int)
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(errno == ERANGE // the value exceeds ULLONG_MAX
|
|
||||||
|| magnitude >= static_cast<unsigned long long>((std::numeric_limits<typename BasicJsonType::size_type>::max)()))) // NOLINT(runtime/int)
|
|
||||||
{
|
|
||||||
// the array index cannot be represented as size_type
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto idx = array_index<BasicJsonType>(reference_token);
|
const auto idx = array_index<BasicJsonType>(reference_token);
|
||||||
if (idx >= ptr->size())
|
if (idx >= ptr->size())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3573,6 +3573,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
{
|
{
|
||||||
using std::swap;
|
using std::swap;
|
||||||
swap(*(m_data.m_value.array), other);
|
swap(*(m_data.m_value.array), other);
|
||||||
|
set_parents();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -3589,6 +3590,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
{
|
{
|
||||||
using std::swap;
|
using std::swap;
|
||||||
swap(*(m_data.m_value.object), other);
|
swap(*(m_data.m_value.object), other);
|
||||||
|
set_parents();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16394,20 +16394,6 @@ class json_pointer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// the reference token consists only of digits at this point (cf. checks
|
|
||||||
// above); however, its numeric value might not be representable, in which
|
|
||||||
// case array_index() would throw out_of_range.404/410 -- contains() must
|
|
||||||
// not throw (see #5395), so such a reference token is treated as "not found"
|
|
||||||
errno = 0; // strtoull() does not reset errno on success
|
|
||||||
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
|
||||||
const unsigned long long magnitude = std::strtoull(reference_token.c_str(), &p_end, 10); // NOLINT(runtime/int)
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(errno == ERANGE // the value exceeds ULLONG_MAX
|
|
||||||
|| magnitude >= static_cast<unsigned long long>((std::numeric_limits<typename BasicJsonType::size_type>::max)()))) // NOLINT(runtime/int)
|
|
||||||
{
|
|
||||||
// the array index cannot be represented as size_type
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto idx = array_index<BasicJsonType>(reference_token);
|
const auto idx = array_index<BasicJsonType>(reference_token);
|
||||||
if (idx >= ptr->size())
|
if (idx >= ptr->size())
|
||||||
{
|
{
|
||||||
@@ -25015,6 +25001,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
{
|
{
|
||||||
using std::swap;
|
using std::swap;
|
||||||
swap(*(m_data.m_value.array), other);
|
swap(*(m_data.m_value.array), other);
|
||||||
|
set_parents();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -25031,6 +25018,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
{
|
{
|
||||||
using std::swap;
|
using std::swap;
|
||||||
swap(*(m_data.m_value.object), other);
|
swap(*(m_data.m_value.object), other);
|
||||||
|
set_parents();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -273,5 +273,36 @@ TEST_CASE("Regression tests for extended diagnostics")
|
|||||||
CHECK(j1["numbers"]["two"] == 2);
|
CHECK(j1["numbers"]["two"] == 2);
|
||||||
CHECK(j1["string"] == "t");
|
CHECK(j1["string"] == "t");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("Regression test - swap(array_t&)/swap(object_t&) must update JSON_DIAGNOSTICS parent pointers")
|
||||||
|
{
|
||||||
|
// swap(array_t&)
|
||||||
|
{
|
||||||
|
json j = json::array();
|
||||||
|
json::array_t arr = {json::array({1})};
|
||||||
|
j.swap(arr);
|
||||||
|
|
||||||
|
// parent pointers of the moved-in elements must point into j, not
|
||||||
|
// into the now-defunct free-standing array_t
|
||||||
|
CHECK_THROWS_WITH_AS(j[0][0].get<std::string>(), "[json.exception.type_error.302] (/0/0) type must be string, but is number", json::type_error);
|
||||||
|
|
||||||
|
// must not trigger assert_invariant() in a debug/assert-enabled build
|
||||||
|
json const k = j;
|
||||||
|
CHECK(k == j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// swap(object_t&)
|
||||||
|
{
|
||||||
|
json o = json::object();
|
||||||
|
json::object_t obj = {{"a", json::array({1})}};
|
||||||
|
o.swap(obj);
|
||||||
|
|
||||||
|
CHECK_THROWS_WITH_AS(o["a"][0].get<std::string>(), "[json.exception.type_error.302] (/a/0) type must be string, but is number", json::type_error);
|
||||||
|
|
||||||
|
// must not trigger assert_invariant() in a debug/assert-enabled build
|
||||||
|
json const p = o;
|
||||||
|
CHECK(p == o);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -319,44 +319,6 @@ TEST_CASE("JSON pointers")
|
|||||||
|
|
||||||
CHECK_THROWS_WITH_AS(j[jp] = 1, throw_msg.c_str(), json::out_of_range&);
|
CHECK_THROWS_WITH_AS(j[jp] = 1, throw_msg.c_str(), json::out_of_range&);
|
||||||
CHECK_THROWS_WITH_AS(j_const[jp] == 1, throw_msg.c_str(), json::out_of_range&);
|
CHECK_THROWS_WITH_AS(j_const[jp] == 1, throw_msg.c_str(), json::out_of_range&);
|
||||||
|
|
||||||
// #5395: contains() must not throw for a reference token that is a
|
|
||||||
// syntactically valid array index but numerically exceeds ULLONG_MAX
|
|
||||||
// (causing strtoull() to set errno to ERANGE) -- it should just report
|
|
||||||
// that the pointer does not resolve to an element
|
|
||||||
CHECK(!j.contains(jp));
|
|
||||||
CHECK(!j_const.contains(jp));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// #5395: same as above, but using the exact reproduction from the issue
|
|
||||||
json::json_pointer const jp("/99999999999999999999");
|
|
||||||
std::string const throw_msg = "[json.exception.out_of_range.404] unresolved reference token '99999999999999999999'";
|
|
||||||
|
|
||||||
CHECK_THROWS_WITH_AS(j[jp] = 1, throw_msg.c_str(), json::out_of_range&);
|
|
||||||
CHECK_THROWS_WITH_AS(j_const[jp] == 1, throw_msg.c_str(), json::out_of_range&);
|
|
||||||
CHECK_THROWS_WITH_AS(j.at(jp) = 1, throw_msg.c_str(), json::out_of_range&);
|
|
||||||
CHECK_THROWS_WITH_AS(j_const.at(jp) == 1, throw_msg.c_str(), json::out_of_range&);
|
|
||||||
|
|
||||||
CHECK(!j.contains(jp));
|
|
||||||
CHECK(!j_const.contains(jp));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// #5395: a reference token that is numerically representable in
|
|
||||||
// unsigned long long but exceeds size_type's max (e.g. ULLONG_MAX
|
|
||||||
// itself on typical 64-bit platforms, where size_type's max equals
|
|
||||||
// ULLONG_MAX) must not make contains() throw either
|
|
||||||
json::json_pointer const jp("/18446744073709551615");
|
|
||||||
std::string const throw_msg = "[json.exception.out_of_range.410] array index 18446744073709551615 exceeds size_type";
|
|
||||||
|
|
||||||
CHECK_THROWS_WITH_AS(j[jp] = 1, throw_msg.c_str(), json::out_of_range&);
|
|
||||||
CHECK_THROWS_WITH_AS(j_const[jp] == 1, throw_msg.c_str(), json::out_of_range&);
|
|
||||||
CHECK_THROWS_WITH_AS(j.at(jp) = 1, throw_msg.c_str(), json::out_of_range&);
|
|
||||||
CHECK_THROWS_WITH_AS(j_const.at(jp) == 1, throw_msg.c_str(), json::out_of_range&);
|
|
||||||
|
|
||||||
CHECK(!j.contains(jp));
|
|
||||||
CHECK(!j_const.contains(jp));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// on some machines, the check below is not constant
|
// on some machines, the check below is not constant
|
||||||
@@ -372,10 +334,6 @@ TEST_CASE("JSON pointers")
|
|||||||
|
|
||||||
CHECK_THROWS_WITH_AS(j[jp] = 1, throw_msg.c_str(), json::out_of_range&);
|
CHECK_THROWS_WITH_AS(j[jp] = 1, throw_msg.c_str(), json::out_of_range&);
|
||||||
CHECK_THROWS_WITH_AS(j_const[jp] == 1, throw_msg.c_str(), json::out_of_range&);
|
CHECK_THROWS_WITH_AS(j_const[jp] == 1, throw_msg.c_str(), json::out_of_range&);
|
||||||
|
|
||||||
// #5395: contains() must not throw for a reference token exceeding size_type's max
|
|
||||||
CHECK(!j.contains(jp));
|
|
||||||
CHECK(!j_const.contains(jp));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DOCTEST_MSVC_SUPPRESS_WARNING_POP
|
DOCTEST_MSVC_SUPPRESS_WARNING_POP
|
||||||
|
|||||||
Reference in New Issue
Block a user