diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 325e819bb..d418fff3a 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -20467,6 +20467,14 @@ class binary_reader return false; } + // validate the type marker up front: otherwise it would only be + // checked when an element is read, and a container with count 0 + // would accept any marker + if (JSON_HEDLEY_UNLIKELY(!is_valid_optimized_type(result.second))) + { + return optimized_type_error(); + } + get_ignore_noop(); if (JSON_HEDLEY_UNLIKELY(current != '#')) { @@ -21963,6 +21971,44 @@ class binary_reader std::size_t bon8_pushback_size = 0; JSON_PRIVATE_UNLESS_TESTED: + /*! + @brief check whether @a marker is a type marker that may follow '$' + UBJSON: Z N T F i U I l L d D H C S [ {; BJData: the numeric markers and C + (BJData's excluded markers are rejected separately). + */ + bool is_valid_optimized_type(const char_int_type marker) const noexcept + { + switch (marker) + { + case 'i': + case 'U': + case 'I': + case 'l': + case 'L': + case 'd': + case 'D': + case 'C': + return true; + case 'Z': + case 'N': + case 'T': + case 'F': + case 'H': + case 'S': + case '[': + case '{': + return input_format != input_format_t::bjdata; + case 'B': + case 'u': + case 'm': + case 'M': + case 'h': + return input_format == input_format_t::bjdata; + default: + return false; + } + } + /*! @brief whether @a marker is excluded from BJData's optimized ND-array types @return whether @a marker is one of 'F', 'H', 'N', 'S', 'T', 'Z', '[', '{' diff --git a/tests/src/unit-bjdata.cpp b/tests/src/unit-bjdata.cpp index af92b48d1..db0663d52 100644 --- a/tests/src/unit-bjdata.cpp +++ b/tests/src/unit-bjdata.cpp @@ -4629,11 +4629,18 @@ TEST_CASE("BJData optimized container type marker is validated for count 0") SECTION("invalid marker") { // 'Z', 'T', 'F', 'N', 'S', 'H', '[' and '{' are excluded in BJData - for (const char marker : {'x', 'E', 'Z', 'T', 'F', 'N', 'S', 'H', '[', '{'}) + for (const char marker : + {'x', 'E', 'Z', 'T', 'F', 'N', 'S', 'H', '[', '{' + }) { - for (const char open : {'[', '{'}) + for (const char open : + {'[', '{' + }) { - for (const std::uint8_t count : {0, 1}) + for (const std::uint8_t count : + { + 0, 1 + }) { CAPTURE(marker) CAPTURE(open) @@ -4656,7 +4663,9 @@ TEST_CASE("BJData optimized container type marker is validated for count 0") SECTION("valid marker") { - for (const char marker : {'i', 'U', 'I', 'u', 'l', 'm', 'L', 'M', 'h', 'd', 'D', 'C'}) + for (const char marker : + {'i', 'U', 'I', 'u', 'l', 'm', 'L', 'M', 'h', 'd', 'D', 'C' + }) { CAPTURE(marker) const std::vector va = {'[', '$', static_cast(marker), '#', 'i', 0}; diff --git a/tests/src/unit-ubjson.cpp b/tests/src/unit-ubjson.cpp index db6ac0f3a..8f6c42810 100644 --- a/tests/src/unit-ubjson.cpp +++ b/tests/src/unit-ubjson.cpp @@ -3354,11 +3354,18 @@ TEST_CASE("UBJSON optimized container type marker is validated for count 0") // the '$' type marker must be a legal marker even if no element follows SECTION("invalid marker") { - for (const char marker : {'x', 'E', 'B', 'u', 'm', 'M', 'h'}) + for (const char marker : + {'x', 'E', 'B', 'u', 'm', 'M', 'h' + }) { - for (const char open : {'[', '{'}) + for (const char open : + {'[', '{' + }) { - for (const std::uint8_t count : {0, 1}) + for (const std::uint8_t count : + { + 0, 1 + }) { CAPTURE(marker) CAPTURE(open) @@ -3381,7 +3388,9 @@ TEST_CASE("UBJSON optimized container type marker is validated for count 0") SECTION("valid marker") { - for (const char marker : {'Z', 'N', 'T', 'F', 'i', 'U', 'I', 'l', 'L', 'd', 'D', 'H', 'C', 'S', '[', '{'}) + for (const char marker : + {'Z', 'N', 'T', 'F', 'i', 'U', 'I', 'l', 'L', 'd', 'D', 'H', 'C', 'S', '[', '{' + }) { CAPTURE(marker) const std::vector va = {'[', '$', static_cast(marker), '#', 'i', 0};