diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 5a0722a18..42ee60389 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -630,6 +630,11 @@ class binary_writer oa.write_character(to_char_type(0xDB)); write_number(static_cast(N)); } + else + { + JSON_THROW(out_of_range::create(412, concat("MessagePack size ", std::to_string(N), " exceeds maximum of ", + std::to_string((std::numeric_limits::max)())), &j)); + } // step 2: write the string oa.write_characters( @@ -659,6 +664,11 @@ class binary_writer oa.write_character(to_char_type(0xDD)); write_number(static_cast(N)); } + else + { + JSON_THROW(out_of_range::create(412, concat("MessagePack size ", std::to_string(N), " exceeds maximum of ", + std::to_string((std::numeric_limits::max)())), &j)); + } // step 2: write each element for (const auto& el : *j.m_data.m_value.array) @@ -736,6 +746,11 @@ class binary_writer oa.write_character(to_char_type(output_type)); write_number(static_cast(N)); } + else + { + JSON_THROW(out_of_range::create(412, concat("MessagePack size ", std::to_string(N), " exceeds maximum of ", + std::to_string((std::numeric_limits::max)())), &j)); + } // step 1.5: if this is an ext type, write the subtype if (use_ext) @@ -777,6 +792,11 @@ class binary_writer oa.write_character(to_char_type(0xDF)); write_number(static_cast(N)); } + else + { + JSON_THROW(out_of_range::create(412, concat("MessagePack size ", std::to_string(N), " exceeds maximum of ", + std::to_string((std::numeric_limits::max)())), &j)); + } // step 2: write each element for (const auto& el : *j.m_data.m_value.object) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 4981c3b02..814b8f411 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -20095,6 +20095,11 @@ class binary_writer oa.write_character(to_char_type(0xDB)); write_number(static_cast(N)); } + else + { + JSON_THROW(out_of_range::create(412, concat("MessagePack size ", std::to_string(N), " exceeds maximum of ", + std::to_string((std::numeric_limits::max)())), &j)); + } // step 2: write the string oa.write_characters( @@ -20124,6 +20129,11 @@ class binary_writer oa.write_character(to_char_type(0xDD)); write_number(static_cast(N)); } + else + { + JSON_THROW(out_of_range::create(412, concat("MessagePack size ", std::to_string(N), " exceeds maximum of ", + std::to_string((std::numeric_limits::max)())), &j)); + } // step 2: write each element for (const auto& el : *j.m_data.m_value.array) @@ -20201,6 +20211,11 @@ class binary_writer oa.write_character(to_char_type(output_type)); write_number(static_cast(N)); } + else + { + JSON_THROW(out_of_range::create(412, concat("MessagePack size ", std::to_string(N), " exceeds maximum of ", + std::to_string((std::numeric_limits::max)())), &j)); + } // step 1.5: if this is an ext type, write the subtype if (use_ext) @@ -20242,6 +20257,11 @@ class binary_writer oa.write_character(to_char_type(0xDF)); write_number(static_cast(N)); } + else + { + JSON_THROW(out_of_range::create(412, concat("MessagePack size ", std::to_string(N), " exceeds maximum of ", + std::to_string((std::numeric_limits::max)())), &j)); + } // step 2: write each element for (const auto& el : *j.m_data.m_value.object) diff --git a/tests/src/unit-msgpack.cpp b/tests/src/unit-msgpack.cpp index 805b03a13..8168b88ae 100644 --- a/tests/src/unit-msgpack.cpp +++ b/tests/src/unit-msgpack.cpp @@ -2150,3 +2150,171 @@ TEST_CASE("MessagePack with std::byte") } } #endif + +template> +struct huge_array : std::vector +{ + using base = std::vector; + using base::base; + + bool fake_size = false; + + std::size_t size() const noexcept + { + if (fake_size) + { + return (std::numeric_limits::max)() + 1ULL; + } + + return base::size(); + } +}; + +using huge_array_json = nlohmann::basic_json < + std::map, huge_array, std::string, bool, std::int64_t, std::uint64_t, + double, std::allocator, nlohmann::adl_serializer, + std::vector, void >; + +TEST_CASE("MessagePack Size above uint32 for array") +{ + huge_array_json j = huge_array_json::array(); + + j.push_back(1); + j.push_back(2); + j.push_back(3); + + auto& array = j.get_ref(); + array.fake_size = true; + + CHECK_THROWS_WITH_AS( + huge_array_json::to_msgpack(j), + "[json.exception.out_of_range.412] MessagePack size 4294967296 exceeds maximum of 4294967295", + json::out_of_range&); + + array.fake_size = false; +} + +template, + typename A = std::allocator>> + struct huge_map : std::map +{ + using base = std::map; + using base::base; + + bool fake_size = false; + + std::size_t size() const noexcept + { + if (fake_size) + { + return static_cast(UINT32_MAX) + 1ULL; + } + + return base::size(); + } +}; + +using huge_object_json = nlohmann::basic_json < + huge_map, + std::vector, + std::string, + bool, + std::int64_t, + std::uint64_t, + double, + std::allocator, + nlohmann::adl_serializer, + std::vector, + void >; + +TEST_CASE("MessagePack Size above uint32 for object") +{ + + huge_object_json j = huge_object_json::object(); + + j["one"] = 1; + j["two"] = 2; + + auto& object = j.get_ref(); + object.fake_size = true; + + CHECK_THROWS_WITH_AS( + huge_object_json::to_msgpack(j), + "[json.exception.out_of_range.412] MessagePack size 4294967296 exceeds maximum of 4294967295", + json::out_of_range&); + + object.fake_size = false; +} + +struct huge_string : std::string +{ + using std::string::string; + + std::size_t size() const noexcept + { + return static_cast(UINT32_MAX) + 1ULL; + } +}; + +using huge_string_json = nlohmann::basic_json < + std::map, + std::vector, + huge_string, + bool, + std::int64_t, + std::uint64_t, + double, + std::allocator, + nlohmann::adl_serializer, + std::vector, + void >; + +TEST_CASE("MessagePack Size above uint32 for string") +{ + + huge_string_json j = "hello"; + + CHECK_THROWS_WITH_AS( + huge_string_json::to_msgpack(j), + "[json.exception.out_of_range.412] MessagePack size 4294967296 exceeds maximum of 4294967295", + json::out_of_range&); +} + +struct huge_binary : std::vector +{ + using std::vector::vector; + + std::size_t size() const noexcept + { + return static_cast(UINT32_MAX) + 1ULL; + } +}; + +using huge_binary_json = nlohmann::basic_json < + std::map, + std::vector, + std::string, + bool, + std::int64_t, + std::uint64_t, + double, + std::allocator, + nlohmann::adl_serializer, + huge_binary, + void >; + +TEST_CASE("MessagePack Size above uint32 for binary") +{ + + huge_binary_json j = huge_binary_json::binary(huge_binary{}); + + j.get_binary().push_back(0x01); + j.get_binary().push_back(0x02); + + CHECK_THROWS_WITH_AS( + huge_binary_json::to_msgpack(j), + "[json.exception.out_of_range.412] MessagePack size 4294967296 exceeds maximum of 4294967295", + json::out_of_range&); +} +