From 046927cc29e4c5ce56adb9777103755318a5e28a Mon Sep 17 00:00:00 2001 From: Qianqian Fang Date: Fri, 3 Jun 2022 02:51:33 -0400 Subject: [PATCH] Fix nlohmann/json#3513, explain is_ndarray flag (#3514) * Fix nlohmann/json#3513, explain is_ndarray flag * add test for ndarray size following H --- .../nlohmann/detail/input/binary_reader.hpp | 28 +++++++++++-------- single_include/nlohmann/json.hpp | 28 +++++++++++-------- tests/src/unit-bjdata.cpp | 14 ++++++---- 3 files changed, 41 insertions(+), 29 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index d259e0448..cbcb41588 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -1938,9 +1938,9 @@ class binary_reader { std::pair size_and_type; size_t dimlen = 0; - bool inside_ndarray = true; + bool no_ndarray = true; - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, inside_ndarray))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, no_ndarray))) { return false; } @@ -1953,7 +1953,7 @@ class binary_reader { for (std::size_t i = 0; i < size_and_type.first; ++i) { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, inside_ndarray, size_and_type.second))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, size_and_type.second))) { return false; } @@ -1965,7 +1965,7 @@ class binary_reader { for (std::size_t i = 0; i < size_and_type.first; ++i) { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, inside_ndarray))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray))) { return false; } @@ -1977,7 +1977,7 @@ class binary_reader { while (current != ']') { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, inside_ndarray, current))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, current))) { return false; } @@ -1990,12 +1990,16 @@ class binary_reader /*! @param[out] result determined size - @param[in,out] inside_ndarray whether the parser is parsing an ND array dimensional vector + @param[in,out] is_ndarray for input, `true` means already inside an ndarray vector + or ndarray dimension is not allowed; `false` means ndarray + is allowed; for output, `true` means an ndarray is found; + is_ndarray can only return `true` when its initial value + is `false` @param[in] prefix type marker if already read, otherwise set to 0 @return whether size determination completed */ - bool get_ubjson_size_value(std::size_t& result, bool& inside_ndarray, char_int_type prefix = 0) + bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0) { if (prefix == 0) { @@ -2130,9 +2134,9 @@ class binary_reader { break; } - if (inside_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array + if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimention vector can only contain integers", "size"), nullptr)); + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimentional vector is not allowed", "size"), nullptr)); } std::vector dim; if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) @@ -2169,7 +2173,7 @@ class binary_reader return false; } } - inside_ndarray = true; + is_ndarray = true; return sax->end_array(); } result = 0; @@ -2650,8 +2654,8 @@ class binary_reader { // get size of following number string std::size_t size{}; - bool inside_ndarray = false; - auto res = get_ubjson_size_value(size, inside_ndarray); + bool no_ndarray = true; + auto res = get_ubjson_size_value(size, no_ndarray); if (JSON_HEDLEY_UNLIKELY(!res)) { return res; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 30386c5e8..91b31eda4 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -10528,9 +10528,9 @@ class binary_reader { std::pair size_and_type; size_t dimlen = 0; - bool inside_ndarray = true; + bool no_ndarray = true; - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, inside_ndarray))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, no_ndarray))) { return false; } @@ -10543,7 +10543,7 @@ class binary_reader { for (std::size_t i = 0; i < size_and_type.first; ++i) { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, inside_ndarray, size_and_type.second))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, size_and_type.second))) { return false; } @@ -10555,7 +10555,7 @@ class binary_reader { for (std::size_t i = 0; i < size_and_type.first; ++i) { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, inside_ndarray))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray))) { return false; } @@ -10567,7 +10567,7 @@ class binary_reader { while (current != ']') { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, inside_ndarray, current))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, current))) { return false; } @@ -10580,12 +10580,16 @@ class binary_reader /*! @param[out] result determined size - @param[in,out] inside_ndarray whether the parser is parsing an ND array dimensional vector + @param[in,out] is_ndarray for input, `true` means already inside an ndarray vector + or ndarray dimension is not allowed; `false` means ndarray + is allowed; for output, `true` means an ndarray is found; + is_ndarray can only return `true` when its initial value + is `false` @param[in] prefix type marker if already read, otherwise set to 0 @return whether size determination completed */ - bool get_ubjson_size_value(std::size_t& result, bool& inside_ndarray, char_int_type prefix = 0) + bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0) { if (prefix == 0) { @@ -10720,9 +10724,9 @@ class binary_reader { break; } - if (inside_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array + if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimention vector can only contain integers", "size"), nullptr)); + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimentional vector is not allowed", "size"), nullptr)); } std::vector dim; if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) @@ -10759,7 +10763,7 @@ class binary_reader return false; } } - inside_ndarray = true; + is_ndarray = true; return sax->end_array(); } result = 0; @@ -11240,8 +11244,8 @@ class binary_reader { // get size of following number string std::size_t size{}; - bool inside_ndarray = false; - auto res = get_ubjson_size_value(size, inside_ndarray); + bool no_ndarray = true; + auto res = get_ubjson_size_value(size, no_ndarray); if (JSON_HEDLEY_UNLIKELY(!res)) { return res; diff --git a/tests/src/unit-bjdata.cpp b/tests/src/unit-bjdata.cpp index c93a5de51..a2ea7820f 100644 --- a/tests/src/unit-bjdata.cpp +++ b/tests/src/unit-bjdata.cpp @@ -2541,7 +2541,7 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(vI, true, false).is_discarded()); } - SECTION("do not accept NTFZ markers in ndarray optimized type") + SECTION("do not accept NTFZ markers in ndarray optimized type (with count)") { json _; std::vector v_N = {'[', '$', 'N', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2}; @@ -2562,7 +2562,7 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(v_Z, true, false).is_discarded()); } - SECTION("do not accept NTFZ markers in ndarray optimized type") + SECTION("do not accept NTFZ markers in ndarray optimized type (without count)") { json _; std::vector v_N = {'[', '$', 'N', '#', '[', 'i', 1, 'i', 2, ']'}; @@ -2746,7 +2746,7 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(vh, true, false).is_discarded()); std::vector vR = {'[', '$', 'i', '#', '[', 'i', 1, '[', ']', ']', 1}; - CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR), "[json.exception.parse_error.113] parse error at byte 8: syntax error while parsing BJData size: ndarray dimention vector can only contain integers", json::parse_error&); + CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR), "[json.exception.parse_error.113] parse error at byte 8: syntax error while parsing BJData size: ndarray dimentional vector is not allowed", json::parse_error&); CHECK(json::from_bjdata(vR, true, false).is_discarded()); std::vector vRo = {'[', '$', 'i', '#', '[', 'i', 0, '{', '}', ']', 1}; @@ -2754,7 +2754,7 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(vRo, true, false).is_discarded()); std::vector vR1 = {'[', '$', 'i', '#', '[', '[', 'i', 1, ']', ']', 1}; - CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR1), "[json.exception.parse_error.113] parse error at byte 6: syntax error while parsing BJData size: ndarray dimention vector can only contain integers", json::parse_error&); + CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR1), "[json.exception.parse_error.113] parse error at byte 6: syntax error while parsing BJData size: ndarray dimentional vector is not allowed", json::parse_error&); CHECK(json::from_bjdata(vR1, true, false).is_discarded()); std::vector vR2 = {'[', '$', 'i', '#', '[', '#', '[', 'i', 1, ']', ']', 1}; @@ -2770,12 +2770,16 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(vR4, true, false).is_discarded()); std::vector vR5 = {'[', '$', 'i', '#', '[', '[', '[', ']', ']', ']'}; - CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR5), "[json.exception.parse_error.113] parse error at byte 6: syntax error while parsing BJData size: ndarray dimention vector can only contain integers", json::parse_error&); + CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR5), "[json.exception.parse_error.113] parse error at byte 6: syntax error while parsing BJData size: ndarray dimentional vector is not allowed", json::parse_error&); CHECK(json::from_bjdata(vR5, true, false).is_discarded()); std::vector vR6 = {'[', '$', 'i', '#', '[', '$', 'i', '#', '[', 'i', '2', 'i', 2, ']'}; CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR6), "[json.exception.parse_error.112] parse error at byte 14: syntax error while parsing BJData size: ndarray can not be recursive", json::parse_error&); CHECK(json::from_bjdata(vR6, true, false).is_discarded()); + + std::vector vH = {'[', 'H', '[', '#', '[', '$', 'i', '#', '[', 'i', '2', 'i', 2, ']'}; + CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vH), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing BJData size: ndarray dimentional vector is not allowed", json::parse_error&); + CHECK(json::from_bjdata(vH, true, false).is_discarded()); } SECTION("objects")