From b205361d8652759b6d850a37b227c8d57ee19005 Mon Sep 17 00:00:00 2001 From: Qianqian Fang Date: Sun, 1 May 2022 16:47:06 -0400 Subject: [PATCH] Handle invalid BJData optimized type, fix #3461 (#3463) * Handle invalid BJData optimized type, fix #3461 * Update unit test to handle bjdata optimized array type error --- .../nlohmann/detail/input/binary_reader.hpp | 7 ++ single_include/nlohmann/json.hpp | 7 ++ tests/src/unit-bjdata.cpp | 93 +++++++++++++------ 3 files changed, 77 insertions(+), 30 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 6474b8b05..75a20ed7b 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -2178,6 +2178,13 @@ class binary_reader std::vector bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type result.second = get(); // must not ignore 'N', because 'N' maybe the type + if (JSON_HEDLEY_UNLIKELY( input_format == input_format_t::bjdata && std::find(bjdx.begin(), bjdx.end(), result.second) != bjdx.end() )) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format, concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr)); + } + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "type") || (input_format == input_format_t::bjdata && std::find(bjdx.begin(), bjdx.end(), result.second) != bjdx.end() ))) { return false; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 949ac14be..bbd84d2be 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -10652,6 +10652,13 @@ class binary_reader std::vector bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type result.second = get(); // must not ignore 'N', because 'N' maybe the type + if (JSON_HEDLEY_UNLIKELY( input_format == input_format_t::bjdata && std::find(bjdx.begin(), bjdx.end(), result.second) != bjdx.end() )) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format, concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr)); + } + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "type") || (input_format == input_format_t::bjdata && std::find(bjdx.begin(), bjdx.end(), result.second) != bjdx.end() ))) { return false; diff --git a/tests/src/unit-bjdata.cpp b/tests/src/unit-bjdata.cpp index bc6c52833..dc2c63122 100644 --- a/tests/src/unit-bjdata.cpp +++ b/tests/src/unit-bjdata.cpp @@ -2408,34 +2408,6 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(json::to_bjdata(j_type), true, true) == j_type); CHECK(json::from_bjdata(json::to_bjdata(j_size), true, true) == j_size); } - - SECTION("do not accept NTFZ markers in ndarray optimized type") - { - json _; - std::vector v_N = {'[', '$', 'N', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2}; - std::vector v_T = {'[', '$', 'T', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2}; - std::vector v_F = {'[', '$', 'F', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2}; - std::vector v_Z = {'[', '$', 'Z', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2}; - - CHECK(json::from_bjdata(v_N, true, true).is_discarded()); - CHECK(json::from_bjdata(v_T, true, true).is_discarded()); - CHECK(json::from_bjdata(v_F, true, true).is_discarded()); - CHECK(json::from_bjdata(v_Z, true, true).is_discarded()); - } - - SECTION("do not accept NTFZ markers in ndarray optimized type") - { - json _; - std::vector v_N = {'[', '$', 'N', '#', '[', 'i', 1, 'i', 2, ']'}; - std::vector v_T = {'[', '$', 'T', '#', '[', 'i', 1, 'i', 2, ']'}; - std::vector v_F = {'[', '$', 'F', '#', '[', 'i', 1, 'i', 2, ']'}; - std::vector v_Z = {'[', '$', 'Z', '#', '[', 'i', 1, 'i', 2, ']'}; - - CHECK(json::from_bjdata(v_N, true, true).is_discarded()); - CHECK(json::from_bjdata(v_T, true, true).is_discarded()); - CHECK(json::from_bjdata(v_F, true, true).is_discarded()); - CHECK(json::from_bjdata(v_Z, true, true).is_discarded()); - } } } @@ -2515,6 +2487,56 @@ TEST_CASE("BJData") CHECK_THROWS_AS(_ = json::from_bjdata(v), json::parse_error&); CHECK_THROWS_WITH(_ = json::from_bjdata(v), "[json.exception.parse_error.112] parse error at byte 4: syntax error while parsing BJData size: expected '#' after type information; last byte: 0x02"); } + + SECTION("do not accept NTFZ markers in ndarray optimized type") + { + json _; + std::vector v_N = {'[', '$', 'N', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2}; + std::vector v_T = {'[', '$', 'T', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2}; + std::vector v_F = {'[', '$', 'F', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2}; + std::vector v_Z = {'[', '$', 'Z', '#', '[', '#', 'i', 2, 'i', 1, 'i', 2}; + + CHECK_THROWS_AS(_ = json::from_bjdata(v_N), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v_N), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x4E is not a permitted optimized array type"); + CHECK(json::from_bjdata(v_N, true, false).is_discarded()); + + CHECK_THROWS_AS(_ = json::from_bjdata(v_T), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v_T), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x54 is not a permitted optimized array type"); + CHECK(json::from_bjdata(v_T, true, false).is_discarded()); + + CHECK_THROWS_AS(_ = json::from_bjdata(v_F), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v_F), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x46 is not a permitted optimized array type"); + CHECK(json::from_bjdata(v_F, true, false).is_discarded()); + + CHECK_THROWS_AS(_ = json::from_bjdata(v_Z), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v_Z), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x5A is not a permitted optimized array type"); + CHECK(json::from_bjdata(v_Z, true, false).is_discarded()); + } + + SECTION("do not accept NTFZ markers in ndarray optimized type") + { + json _; + std::vector v_N = {'[', '$', 'N', '#', '[', 'i', 1, 'i', 2, ']'}; + std::vector v_T = {'[', '$', 'T', '#', '[', 'i', 1, 'i', 2, ']'}; + std::vector v_F = {'[', '$', 'F', '#', '[', 'i', 1, 'i', 2, ']'}; + std::vector v_Z = {'[', '$', 'Z', '#', '[', 'i', 1, 'i', 2, ']'}; + + CHECK_THROWS_AS(_ = json::from_bjdata(v_N), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v_N), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x4E is not a permitted optimized array type"); + CHECK(json::from_bjdata(v_N, true, false).is_discarded()); + + CHECK_THROWS_AS(_ = json::from_bjdata(v_T), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v_T), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x54 is not a permitted optimized array type"); + CHECK(json::from_bjdata(v_T, true, false).is_discarded()); + + CHECK_THROWS_AS(_ = json::from_bjdata(v_F), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v_F), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x46 is not a permitted optimized array type"); + CHECK(json::from_bjdata(v_F, true, false).is_discarded()); + + CHECK_THROWS_AS(_ = json::from_bjdata(v_Z), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v_Z), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x5A is not a permitted optimized array type"); + CHECK(json::from_bjdata(v_Z, true, false).is_discarded()); + } } SECTION("strings") @@ -2626,6 +2648,11 @@ TEST_CASE("BJData") CHECK_THROWS_AS(_ = json::from_bjdata(vU), json::parse_error&); CHECK_THROWS_WITH(_ = json::from_bjdata(vU), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing BJData value: unexpected end of input"); CHECK(json::from_bjdata(vU, true, false).is_discarded()); + + std::vector v1 = {'[', '$', '['}; + CHECK_THROWS_AS(_ = json::from_bjdata(v1), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v1), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x5B is not a permitted optimized array type"); + CHECK(json::from_bjdata(v1, true, false).is_discarded()); } SECTION("arrays") @@ -3188,14 +3215,20 @@ TEST_CASE("Universal Binary JSON Specification Examples 1") { SECTION("Array") { + json _; std::vector v = {'[', '$', 'N', '#', 'I', 0x00, 0x02}; - CHECK(json::from_bjdata(v, true, true).is_discarded()); + CHECK_THROWS_AS(_ = json::from_bjdata(v), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x4E is not a permitted optimized array type"); + CHECK(json::from_bjdata(v, true, false).is_discarded()); } SECTION("Object") { + json _; std::vector v = {'{', '$', 'Z', '#', 'i', 3, 'i', 4, 'n', 'a', 'm', 'e', 'i', 8, 'p', 'a', 's', 's', 'w', 'o', 'r', 'd', 'i', 5, 'e', 'm', 'a', 'i', 'l'}; - CHECK(json::from_bjdata(v, true, true).is_discarded()); + CHECK_THROWS_AS(_ = json::from_bjdata(v), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v), "[json.exception.parse_error.112] parse error at byte 3: syntax error while parsing BJData type: marker 0x5A is not a permitted optimized array type"); + CHECK(json::from_bjdata(v, true, false).is_discarded()); } } }