diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index 18b66e2345..8e97b04d60 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -329,8 +329,10 @@ class json_pointer @throw parse_error.109 if an array index begins not with a digit @throw out_of_range.404 if string @a s could not be converted to an integer */ - static int array_index(const std::string& s) + static typename BasicJsonType::size_type array_index(const std::string& s) { + using size_type = typename BasicJsonType::size_type; + // error condition (cf. RFC 6901, Sect. 4) if (JSON_HEDLEY_UNLIKELY(s.size() > 1 and s[0] == '0')) { @@ -346,10 +348,10 @@ class json_pointer } std::size_t processed_chars = 0; - int res = 0; + size_type res = 0; JSON_TRY { - res = std::stoi(s, &processed_chars); + res = std::stoull(s, &processed_chars); } JSON_CATCH(std::out_of_range&) { @@ -421,7 +423,7 @@ class json_pointer case detail::value_t::array: { // create an entry in the array - result = &result->operator[](static_cast(array_index(reference_token))); + result = &result->operator[](array_index(reference_token)); break; } @@ -499,8 +501,7 @@ class json_pointer else { // convert array index to number; unchecked access - ptr = &ptr->operator[]( - static_cast(array_index(reference_token))); + ptr = &ptr->operator[](array_index(reference_token)); } break; } @@ -544,7 +545,7 @@ class json_pointer } // note: at performs range check - ptr = &ptr->at(static_cast(array_index(reference_token))); + ptr = &ptr->at(array_index(reference_token)); break; } @@ -594,8 +595,7 @@ class json_pointer } // use unchecked array access - ptr = &ptr->operator[]( - static_cast(array_index(reference_token))); + ptr = &ptr->operator[](array_index(reference_token)); break; } @@ -638,7 +638,7 @@ class json_pointer } // note: at performs range check - ptr = &ptr->at(static_cast(array_index(reference_token))); + ptr = &ptr->at(array_index(reference_token)); break; } @@ -702,7 +702,7 @@ class json_pointer } } - const auto idx = static_cast(array_index(reference_token)); + const auto idx = array_index(reference_token); if (idx >= ptr->size()) { // index out of range diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 790ecd4b25..048307b3a9 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -8179,7 +8179,7 @@ class basic_json else { const auto idx = json_pointer::array_index(last_path); - if (JSON_HEDLEY_UNLIKELY(static_cast(idx) > parent.size())) + if (JSON_HEDLEY_UNLIKELY(idx > parent.size())) { // avoid undefined behavior JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); @@ -8222,7 +8222,7 @@ class basic_json else if (parent.is_array()) { // note erase performs range check - parent.erase(static_cast(json_pointer::array_index(last_path))); + parent.erase(json_pointer::array_index(last_path)); } }; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 22fc0e3300..845aa39261 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -11361,8 +11361,10 @@ class json_pointer @throw parse_error.109 if an array index begins not with a digit @throw out_of_range.404 if string @a s could not be converted to an integer */ - static int array_index(const std::string& s) + static typename BasicJsonType::size_type array_index(const std::string& s) { + using size_type = typename BasicJsonType::size_type; + // error condition (cf. RFC 6901, Sect. 4) if (JSON_HEDLEY_UNLIKELY(s.size() > 1 and s[0] == '0')) { @@ -11378,10 +11380,10 @@ class json_pointer } std::size_t processed_chars = 0; - int res = 0; + size_type res = 0; JSON_TRY { - res = std::stoi(s, &processed_chars); + res = std::stoull(s, &processed_chars); } JSON_CATCH(std::out_of_range&) { @@ -11453,7 +11455,7 @@ class json_pointer case detail::value_t::array: { // create an entry in the array - result = &result->operator[](static_cast(array_index(reference_token))); + result = &result->operator[](array_index(reference_token)); break; } @@ -11531,8 +11533,7 @@ class json_pointer else { // convert array index to number; unchecked access - ptr = &ptr->operator[]( - static_cast(array_index(reference_token))); + ptr = &ptr->operator[](array_index(reference_token)); } break; } @@ -11576,7 +11577,7 @@ class json_pointer } // note: at performs range check - ptr = &ptr->at(static_cast(array_index(reference_token))); + ptr = &ptr->at(array_index(reference_token)); break; } @@ -11626,8 +11627,7 @@ class json_pointer } // use unchecked array access - ptr = &ptr->operator[]( - static_cast(array_index(reference_token))); + ptr = &ptr->operator[](array_index(reference_token)); break; } @@ -11670,7 +11670,7 @@ class json_pointer } // note: at performs range check - ptr = &ptr->at(static_cast(array_index(reference_token))); + ptr = &ptr->at(array_index(reference_token)); break; } @@ -11734,7 +11734,7 @@ class json_pointer } } - const auto idx = static_cast(array_index(reference_token)); + const auto idx = array_index(reference_token); if (idx >= ptr->size()) { // index out of range @@ -23971,7 +23971,7 @@ class basic_json else { const auto idx = json_pointer::array_index(last_path); - if (JSON_HEDLEY_UNLIKELY(static_cast(idx) > parent.size())) + if (JSON_HEDLEY_UNLIKELY(idx > parent.size())) { // avoid undefined behavior JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); @@ -24014,7 +24014,7 @@ class basic_json else if (parent.is_array()) { // note erase performs range check - parent.erase(static_cast(json_pointer::array_index(last_path))); + parent.erase(json_pointer::array_index(last_path)); } }; diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index ca11efa428..7b6d1c598d 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -348,12 +348,16 @@ TEST_CASE("JSON pointers") CHECK_THROWS_WITH(j_const["/1+1"_json_pointer] == 1, "[json.exception.out_of_range.404] unresolved reference token '1+1'"); - CHECK_THROWS_AS(j["/111111111111111111111111"_json_pointer] = 1, json::out_of_range&); - CHECK_THROWS_WITH(j["/111111111111111111111111"_json_pointer] = 1, - "[json.exception.out_of_range.404] unresolved reference token '111111111111111111111111'"); - CHECK_THROWS_AS(j_const["/111111111111111111111111"_json_pointer] == 1, json::out_of_range&); - CHECK_THROWS_WITH(j_const["/111111111111111111111111"_json_pointer] == 1, - "[json.exception.out_of_range.404] unresolved reference token '111111111111111111111111'"); + { + auto too_large_index = std::to_string((std::numeric_limits::max)()) + "1"; + json::json_pointer jp(std::string("/") + too_large_index); + std::string throw_msg = std::string("[json.exception.out_of_range.404] unresolved reference token '") + too_large_index + "'"; + + CHECK_THROWS_AS(j[jp] = 1, json::out_of_range&); + CHECK_THROWS_WITH(j[jp] == 1, throw_msg.c_str()); + CHECK_THROWS_AS(j_const[jp] == 1, json::out_of_range&); + CHECK_THROWS_WITH(j_const[jp] == 1, throw_msg.c_str()); + } CHECK_THROWS_AS(j.at("/one"_json_pointer) = 1, json::parse_error&); CHECK_THROWS_WITH(j.at("/one"_json_pointer) = 1,