From dd24e2dffd734c24d71cd79d09dee32d72dde7ca Mon Sep 17 00:00:00 2001 From: Yash Bavadiya <77008538+xevrion@users.noreply.github.com> Date: Fri, 31 Jul 2026 03:14:31 +0530 Subject: [PATCH] check all BSON reads and add an EOF check for booleans (#5332) Signed-off-by: Yash Bavadiya --- .../nlohmann/detail/input/binary_reader.hpp | 18 +++++++--- single_include/nlohmann/json.hpp | 18 +++++++--- tests/src/unit-bson.cpp | 35 +++++++++++++++++++ 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 3f03dd0b3..8ec8436df 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -197,7 +197,10 @@ class binary_reader { const std::size_t document_start = chars_read; std::int32_t document_size{}; - get_number(input_format_t::bson, document_size); + if (!get_number(input_format_t::bson, document_size)) + { + return false; + } if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size()))) { @@ -287,7 +290,10 @@ class binary_reader // All BSON binary values have a subtype std::uint8_t subtype{}; - get_number(input_format_t::bson, subtype); + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::bson, subtype))) + { + return false; + } result.set_subtype(subtype); return get_binary(input_format_t::bson, len, result); @@ -340,7 +346,8 @@ class binary_reader case 0x08: // boolean { - return sax->boolean(get() != 0); + std::uint8_t value{}; + return get_number(input_format_t::bson, value) && sax->boolean(value != 0); } case 0x0A: // null @@ -431,7 +438,10 @@ class binary_reader { const std::size_t document_start = chars_read; std::int32_t document_size{}; - get_number(input_format_t::bson, document_size); + if (!get_number(input_format_t::bson, document_size)) + { + return false; + } if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size()))) { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 2878b428a..b580130c3 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -10746,7 +10746,10 @@ class binary_reader { const std::size_t document_start = chars_read; std::int32_t document_size{}; - get_number(input_format_t::bson, document_size); + if (!get_number(input_format_t::bson, document_size)) + { + return false; + } if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size()))) { @@ -10836,7 +10839,10 @@ class binary_reader // All BSON binary values have a subtype std::uint8_t subtype{}; - get_number(input_format_t::bson, subtype); + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::bson, subtype))) + { + return false; + } result.set_subtype(subtype); return get_binary(input_format_t::bson, len, result); @@ -10889,7 +10895,8 @@ class binary_reader case 0x08: // boolean { - return sax->boolean(get() != 0); + std::uint8_t value{}; + return get_number(input_format_t::bson, value) && sax->boolean(value != 0); } case 0x0A: // null @@ -10980,7 +10987,10 @@ class binary_reader { const std::size_t document_start = chars_read; std::int32_t document_size{}; - get_number(input_format_t::bson, document_size); + if (!get_number(input_format_t::bson, document_size)) + { + return false; + } if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size()))) { diff --git a/tests/src/unit-bson.cpp b/tests/src/unit-bson.cpp index fbd83faad..75a2aa94c 100644 --- a/tests/src/unit-bson.cpp +++ b/tests/src/unit-bson.cpp @@ -825,6 +825,41 @@ TEST_CASE("Incomplete BSON Input") CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); } + SECTION("Incomplete BSON Input 5") + { + std::vector const incomplete_bson = + { + 0x09, 0x00, 0x00, 0x00, // size (little endian) + 0x08, // entry: boolean + 'b', '\x00' // key, unexpected EOF before the value + }; + + json _; + CHECK_THROWS_WITH_AS(_ = json::from_bson(incomplete_bson), "[json.exception.parse_error.110] parse error at byte 8: syntax error while parsing BSON number: unexpected end of input", json::parse_error&); + CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); + + SaxCountdown scp(0); + CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); + } + + SECTION("Incomplete BSON Input 6") + { + std::vector const incomplete_bson = + { + 0x0F, 0x00, 0x00, 0x00, // size (little endian) + 0x05, // entry: binary + 'b', '\x00', // key + 0x00, 0x00, 0x00, 0x00 // length, unexpected EOF before the subtype + }; + + json _; + CHECK_THROWS_WITH_AS(_ = json::from_bson(incomplete_bson), "[json.exception.parse_error.110] parse error at byte 12: syntax error while parsing BSON number: unexpected end of input", json::parse_error&); + CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); + + SaxCountdown scp(0); + CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); + } + SECTION("Improve coverage") { SECTION("key")