From bfc003cadf5c024b09f8538ba95d0d7bc9960ffd Mon Sep 17 00:00:00 2001 From: chenguoping Date: Tue, 17 Mar 2020 20:49:28 +0800 Subject: [PATCH 1/4] catch exceptions for json_point : /xx/+99 --- include/nlohmann/detail/json_pointer.hpp | 54 ++++++------------------ single_include/nlohmann/json.hpp | 54 ++++++------------------ 2 files changed, 28 insertions(+), 80 deletions(-) diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index 87af3423..c8fd2825 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -329,6 +329,20 @@ class json_pointer */ static int array_index(const std::string& s) { + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 and s[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + s + + "' must not begin with '0'")); + } + + // error condition (cf. RFC 6901, Sect. 4 & Sect. 7) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 and not (s[0] >= '1' and s[0] <= '9'))) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number")); + } + std::size_t processed_chars = 0; const int res = std::stoi(s, &processed_chars); @@ -474,14 +488,6 @@ class json_pointer case detail::value_t::array: { - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - if (reference_token == "-") { // explicitly treat "-" as index beyond the end @@ -541,14 +547,6 @@ class json_pointer ") is out of range")); } - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - // note: at performs range check JSON_TRY { @@ -606,14 +604,6 @@ class json_pointer ") is out of range")); } - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - // use unchecked array access JSON_TRY { @@ -665,14 +655,6 @@ class json_pointer ") is out of range")); } - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - // note: at performs range check JSON_TRY { @@ -724,14 +706,6 @@ class json_pointer return false; } - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - JSON_TRY { const auto idx = static_cast(array_index(reference_token)); diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 68916fa0..ca3e8171 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -10403,6 +10403,20 @@ class json_pointer */ static int array_index(const std::string& s) { + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 and s[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + s + + "' must not begin with '0'")); + } + + // error condition (cf. RFC 6901, Sect. 4 & Sect. 7) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 and not (s[0] >= '1' and s[0] <= '9'))) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number")); + } + std::size_t processed_chars = 0; const int res = std::stoi(s, &processed_chars); @@ -10548,14 +10562,6 @@ class json_pointer case detail::value_t::array: { - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - if (reference_token == "-") { // explicitly treat "-" as index beyond the end @@ -10615,14 +10621,6 @@ class json_pointer ") is out of range")); } - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - // note: at performs range check JSON_TRY { @@ -10680,14 +10678,6 @@ class json_pointer ") is out of range")); } - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - // use unchecked array access JSON_TRY { @@ -10739,14 +10729,6 @@ class json_pointer ") is out of range")); } - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - // note: at performs range check JSON_TRY { @@ -10798,14 +10780,6 @@ class json_pointer return false; } - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - JSON_TRY { const auto idx = static_cast(array_index(reference_token)); From dcd3a6c62bf3bb6355faf17afc24374e077f6f20 Mon Sep 17 00:00:00 2001 From: chenguoping Date: Mon, 23 Mar 2020 17:24:47 +0800 Subject: [PATCH 2/4] move the catch of std::invalid_argument into array_index() --- include/nlohmann/detail/json_pointer.hpp | 79 +++++++----------------- single_include/nlohmann/json.hpp | 79 +++++++----------------- 2 files changed, 44 insertions(+), 114 deletions(-) diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index c8fd2825..0acf924e 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -344,7 +344,15 @@ class json_pointer } std::size_t processed_chars = 0; - const int res = std::stoi(s, &processed_chars); + int res = 0; + JSON_TRY + { + res = std::stoi(s, &processed_chars); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number")); + } // check if the string was completely read if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size())) @@ -411,14 +419,7 @@ class json_pointer case detail::value_t::array: { // create an entry in the array - JSON_TRY - { - result = &result->operator[](static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } + result = &result->operator[](static_cast(array_index(reference_token))); break; } @@ -496,15 +497,8 @@ class json_pointer else { // convert array index to number; unchecked access - JSON_TRY - { - ptr = &ptr->operator[]( - static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } + ptr = &ptr->operator[]( + static_cast(array_index(reference_token))); } break; } @@ -548,14 +542,7 @@ class json_pointer } // note: at performs range check - JSON_TRY - { - ptr = &ptr->at(static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } + ptr = &ptr->at(static_cast(array_index(reference_token))); break; } @@ -605,15 +592,8 @@ class json_pointer } // use unchecked array access - JSON_TRY - { - ptr = &ptr->operator[]( - static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } + ptr = &ptr->operator[]( + static_cast(array_index(reference_token))); break; } @@ -656,14 +636,7 @@ class json_pointer } // note: at performs range check - JSON_TRY - { - ptr = &ptr->at(static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } + ptr = &ptr->at(static_cast(array_index(reference_token))); break; } @@ -706,22 +679,14 @@ class json_pointer return false; } - JSON_TRY + const auto idx = static_cast(array_index(reference_token)); + if (idx >= ptr->size()) { - const auto idx = static_cast(array_index(reference_token)); - if (idx >= ptr->size()) - { - // index out of range - return false; - } + // index out of range + return false; + } - ptr = &ptr->operator[](idx); - break; - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } + ptr = &ptr->operator[](idx); break; } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index ca3e8171..5c93426e 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -10418,7 +10418,15 @@ class json_pointer } std::size_t processed_chars = 0; - const int res = std::stoi(s, &processed_chars); + int res = 0; + JSON_TRY + { + res = std::stoi(s, &processed_chars); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number")); + } // check if the string was completely read if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size())) @@ -10485,14 +10493,7 @@ class json_pointer case detail::value_t::array: { // create an entry in the array - JSON_TRY - { - result = &result->operator[](static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } + result = &result->operator[](static_cast(array_index(reference_token))); break; } @@ -10570,15 +10571,8 @@ class json_pointer else { // convert array index to number; unchecked access - JSON_TRY - { - ptr = &ptr->operator[]( - static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } + ptr = &ptr->operator[]( + static_cast(array_index(reference_token))); } break; } @@ -10622,14 +10616,7 @@ class json_pointer } // note: at performs range check - JSON_TRY - { - ptr = &ptr->at(static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } + ptr = &ptr->at(static_cast(array_index(reference_token))); break; } @@ -10679,15 +10666,8 @@ class json_pointer } // use unchecked array access - JSON_TRY - { - ptr = &ptr->operator[]( - static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } + ptr = &ptr->operator[]( + static_cast(array_index(reference_token))); break; } @@ -10730,14 +10710,7 @@ class json_pointer } // note: at performs range check - JSON_TRY - { - ptr = &ptr->at(static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } + ptr = &ptr->at(static_cast(array_index(reference_token))); break; } @@ -10780,22 +10753,14 @@ class json_pointer return false; } - JSON_TRY + const auto idx = static_cast(array_index(reference_token)); + if (idx >= ptr->size()) { - const auto idx = static_cast(array_index(reference_token)); - if (idx >= ptr->size()) - { - // index out of range - return false; - } + // index out of range + return false; + } - ptr = &ptr->operator[](idx); - break; - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } + ptr = &ptr->operator[](idx); break; } From e07686f0c72fd7a13ec1b8e3a13aa0b2d2f592c8 Mon Sep 17 00:00:00 2001 From: chenguoping Date: Wed, 25 Mar 2020 15:56:45 +0800 Subject: [PATCH 3/4] update array_index() and add testcases --- include/nlohmann/detail/json_pointer.hpp | 4 ++-- single_include/nlohmann/json.hpp | 4 ++-- test/src/unit-json_pointer.cpp | 28 ++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index 0acf924e..ebf3ca8a 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -349,9 +349,9 @@ class json_pointer { res = std::stoi(s, &processed_chars); } - JSON_CATCH(std::invalid_argument&) + JSON_CATCH(std::out_of_range&) { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number")); + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); } // check if the string was completely read diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 5c93426e..686cd52c 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -10423,9 +10423,9 @@ class json_pointer { res = std::stoi(s, &processed_chars); } - JSON_CATCH(std::invalid_argument&) + JSON_CATCH(std::out_of_range&) { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number")); + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); } // check if the string was completely read diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index 3cfd8dad..1655a458 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -332,6 +332,34 @@ TEST_CASE("JSON pointers") CHECK_THROWS_WITH(j_const.at("/one"_json_pointer) == 1, "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); + CHECK_THROWS_AS(j["/+1"_json_pointer] = 1, json::parse_error&); + CHECK_THROWS_WITH(j["/+1"_json_pointer] = 1, + "[json.exception.parse_error.109] parse error: array index '+1' is not a number"); + CHECK_THROWS_AS(j_const["/+1"_json_pointer] == 1, json::parse_error&); + CHECK_THROWS_WITH(j_const["/+1"_json_pointer] == 1, + "[json.exception.parse_error.109] parse error: array index '+1' is not a number"); + + CHECK_THROWS_AS(j["/1+1"_json_pointer] = 1, json::out_of_range&); + CHECK_THROWS_WITH(j["/1+1"_json_pointer] = 1, + "[json.exception.out_of_range.404] unresolved reference token '1+1'"); + CHECK_THROWS_AS(j_const["/1+1"_json_pointer] == 1, json::out_of_range&); + 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'"); + + CHECK_THROWS_AS(j.at("/one"_json_pointer) = 1, json::parse_error&); + CHECK_THROWS_WITH(j.at("/one"_json_pointer) = 1, + "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); + CHECK_THROWS_AS(j_const.at("/one"_json_pointer) == 1, json::parse_error&); + CHECK_THROWS_WITH(j_const.at("/one"_json_pointer) == 1, + "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); + CHECK_THROWS_AS(j.contains("/one"_json_pointer), json::parse_error&); CHECK_THROWS_WITH(j.contains("/one"_json_pointer), "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); From 34cf7b7a48317573bcd119effbefe647f10cfd5e Mon Sep 17 00:00:00 2001 From: chenguoping Date: Tue, 7 Apr 2020 10:00:21 +0800 Subject: [PATCH 4/4] just restart ci --- include/nlohmann/detail/json_pointer.hpp | 2 +- single_include/nlohmann/json.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index ebf3ca8a..6bdcedd5 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -337,7 +337,7 @@ class json_pointer "' must not begin with '0'")); } - // error condition (cf. RFC 6901, Sect. 4 & Sect. 7) + // error condition (cf. RFC 6901, Sect. 4) if (JSON_HEDLEY_UNLIKELY(s.size() > 1 and not (s[0] >= '1' and s[0] <= '9'))) { JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number")); diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 686cd52c..57a697fa 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -10411,7 +10411,7 @@ class json_pointer "' must not begin with '0'")); } - // error condition (cf. RFC 6901, Sect. 4 & Sect. 7) + // error condition (cf. RFC 6901, Sect. 4) if (JSON_HEDLEY_UNLIKELY(s.size() > 1 and not (s[0] >= '1' and s[0] <= '9'))) { JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number"));