From 13730235f2430e0071cdd5e61479eeb1e7eb0e4f Mon Sep 17 00:00:00 2001 From: Qianqian Fang Date: Sat, 18 Jun 2022 13:12:22 -0400 Subject: [PATCH 1/2] BJData dimension length can not be string_t::npos, fix #3541 (#3543) * BJData dimension length can not be string_t::npos, fix #3541 * handle error messages on 32bit machine * add explanation to why size can not be string_t::npos * add test cases to 32bit unit test Co-authored-by: Florian Albrechtskirchinger --- include/nlohmann/detail/input/binary_reader.hpp | 2 +- single_include/nlohmann/json.hpp | 2 +- tests/src/unit-32bit.cpp | 15 +++++++++++++++ tests/src/unit-bjdata.cpp | 12 ++++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index f5871ddf6..103f7a752 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -2179,7 +2179,7 @@ class binary_reader for (auto i : dim) { result *= i; - if (result == 0) // because dim elements shall not have zeros, result = 0 means overflow happened + if (result == 0 || result == string_t::npos) // because dim elements shall not have zeros, result = 0 means overflow happened; it also can't be string_t::npos as it is used to initialize size in get_ubjson_size_type() { return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 98c8dd664..834c6fc87 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -10879,7 +10879,7 @@ class binary_reader for (auto i : dim) { result *= i; - if (result == 0) // because dim elements shall not have zeros, result = 0 means overflow happened + if (result == 0 || result == string_t::npos) // because dim elements shall not have zeros, result = 0 means overflow happened; it also can't be string_t::npos as it is used to initialize size in get_ubjson_size_type() { return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); } diff --git a/tests/src/unit-32bit.cpp b/tests/src/unit-32bit.cpp index 25da44f4d..cbe07b49f 100644 --- a/tests/src/unit-32bit.cpp +++ b/tests/src/unit-32bit.cpp @@ -98,6 +98,19 @@ TEST_CASE("BJData") { SECTION("array") { + SECTION("optimized array: negative size") + { + std::vector vM = {'[', '$', 'M', '#', '[', 'I', 0x00, 0x20, 'M', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xFF, ']'}; + std::vector vMX = {'[', '$', 'U', '#', '[', 'M', 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 'U', 0x01, ']'}; + + json _; + CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vM), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&); + CHECK(json::from_bjdata(vM, true, false).is_discarded()); + + CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vMX), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&); + CHECK(json::from_bjdata(vMX, true, false).is_discarded()); + } + SECTION("optimized array: integer value overflow") { std::vector vL = {'[', '#', 'L', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F}; @@ -105,8 +118,10 @@ TEST_CASE("BJData") json _; CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vL), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&); + CHECK(json::from_bjdata(vL, true, false).is_discarded()); CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vM), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&); + CHECK(json::from_bjdata(vM, true, false).is_discarded()); } } } diff --git a/tests/src/unit-bjdata.cpp b/tests/src/unit-bjdata.cpp index ab046a602..7442ea588 100644 --- a/tests/src/unit-bjdata.cpp +++ b/tests/src/unit-bjdata.cpp @@ -2620,6 +2620,7 @@ TEST_CASE("BJData") std::vector vl = {'[', '#', 'l', 0x00, 0x00, 0x00, 0xF2}; std::vector vL = {'[', '#', 'L', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF3}; std::vector vM = {'[', '$', 'M', '#', '[', 'I', 0x00, 0x20, 'M', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xFF, ']'}; + std::vector vMX = {'[', '$', 'U', '#', '[', 'M', 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 'U', 0x01, ']'}; json _; CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v1), "[json.exception.parse_error.113] parse error at byte 4: syntax error while parsing BJData size: count in an optimized container must be positive", json::parse_error&); @@ -2651,8 +2652,17 @@ TEST_CASE("BJData") #if SIZE_MAX != 0xffffffff CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vM), "[json.exception.out_of_range.408] syntax error while parsing BJData size: excessive ndarray size caused overflow", json::out_of_range&); +#else + CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vM), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&); #endif CHECK(json::from_bjdata(vM, true, false).is_discarded()); + +#if SIZE_MAX != 0xffffffff + CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vMX), "[json.exception.out_of_range.408] syntax error while parsing BJData size: excessive ndarray size caused overflow", json::out_of_range&); +#else + CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vMX), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&); +#endif + CHECK(json::from_bjdata(vMX, true, false).is_discarded()); } SECTION("optimized array: integer value overflow") @@ -2663,10 +2673,12 @@ TEST_CASE("BJData") json _; #if SIZE_MAX == 0xffffffff CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vL), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&); + CHECK(json::from_bjdata(vL, true, false).is_discarded()); #endif #if SIZE_MAX == 0xffffffff CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vM), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&); + CHECK(json::from_bjdata(vM, true, false).is_discarded()); #endif } From 87cda1d6646592ac5866dc703c8e1839046a6806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E5=B0=91=E9=94=9F?= Date: Sun, 19 Jun 2022 01:14:03 +0800 Subject: [PATCH 2/2] Use `std::iterator_traits` to extract `iterator_category` (#3544) * Use `std::iterator_traits` to extract `iterator_category` In third-party STL implementations, `array_t::iterator` might be a pointer (e.g., `vector` in [EASTL](https://github.com/electronicarts/EASTL)) rather than a class, in which case directly using `array_t::iterator::iterator_category` is invalid. This commit fixes it with `std::iterator_traits`, which handles pointers correctly. * add the changes to the single-header version --- include/nlohmann/detail/iterators/iter_impl.hpp | 2 +- single_include/nlohmann/json.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp index 81c61b3e0..028de4047 100644 --- a/include/nlohmann/detail/iterators/iter_impl.hpp +++ b/include/nlohmann/detail/iterators/iter_impl.hpp @@ -53,7 +53,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci "iter_impl only accepts (const) basic_json"); // superficial check for the LegacyBidirectionalIterator named requirement static_assert(std::is_base_of::value - && std::is_base_of::value, + && std::is_base_of::iterator_category>::value, "basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement."); public: diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 834c6fc87..50e5c805c 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -12393,7 +12393,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci "iter_impl only accepts (const) basic_json"); // superficial check for the LegacyBidirectionalIterator named requirement static_assert(std::is_base_of::value - && std::is_base_of::value, + && std::is_base_of::iterator_category>::value, "basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement."); public: