:bug: fix BSON conformance issue

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp
index 2a89d2b..f4df800 100644
--- a/include/nlohmann/detail/input/binary_reader.hpp
+++ b/include/nlohmann/detail/input/binary_reader.hpp
@@ -170,7 +170,10 @@
     bool parse_bson_internal()
     {
         std::int32_t document_size{};
-        get_number<std::int32_t, true>(input_format_t::bson, document_size);
+        if (JSON_HEDLEY_UNLIKELY((!get_number<std::int32_t, true>(input_format_t::bson, document_size))))
+        {
+            return false;
+        }
 
         if (JSON_HEDLEY_UNLIKELY(document_size < 5))
         {
@@ -181,9 +184,10 @@
                                             "document size"), nullptr));
         }
 
-        // chars_read now points just past the 4-byte size field;
-        // the document started 4 bytes earlier and must end at start + document_size.
-        const std::size_t expected_end = chars_read + static_cast<std::size_t>(document_size) - 4;
+        // The document begins at the size field and ends document_size bytes later
+        // (including the size field itself and the trailing 0x00 terminator).
+        const std::size_t document_start = chars_read - sizeof(std::int32_t);
+        const std::size_t expected_end = document_start + static_cast<std::size_t>(document_size);
 
         if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))
         {
@@ -434,7 +438,10 @@
     bool parse_bson_array()
     {
         std::int32_t document_size{};
-        get_number<std::int32_t, true>(input_format_t::bson, document_size);
+        if (JSON_HEDLEY_UNLIKELY((!get_number<std::int32_t, true>(input_format_t::bson, document_size))))
+        {
+            return false;
+        }
 
         if (JSON_HEDLEY_UNLIKELY(document_size < 5))
         {
@@ -445,9 +452,10 @@
                                             "document size"), nullptr));
         }
 
-        // chars_read now points just past the 4-byte size field;
-        // the document started 4 bytes earlier and must end at start + document_size.
-        const std::size_t expected_end = chars_read + static_cast<std::size_t>(document_size) - 4;
+        // The document begins at the size field and ends document_size bytes later
+        // (including the size field itself and the trailing 0x00 terminator).
+        const std::size_t document_start = chars_read - sizeof(std::int32_t);
+        const std::size_t expected_end = document_start + static_cast<std::size_t>(document_size);
 
         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 406df31..3d26979 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -10312,7 +10312,10 @@
     bool parse_bson_internal()
     {
         std::int32_t document_size{};
-        get_number<std::int32_t, true>(input_format_t::bson, document_size);
+        if (JSON_HEDLEY_UNLIKELY((!get_number<std::int32_t, true>(input_format_t::bson, document_size))))
+        {
+            return false;
+        }
 
         if (JSON_HEDLEY_UNLIKELY(document_size < 5))
         {
@@ -10323,9 +10326,10 @@
                                             "document size"), nullptr));
         }
 
-        // chars_read now points just past the 4-byte size field;
-        // the document started 4 bytes earlier and must end at start + document_size.
-        const std::size_t expected_end = chars_read + static_cast<std::size_t>(document_size) - 4;
+        // The document begins at the size field and ends document_size bytes later
+        // (including the size field itself and the trailing 0x00 terminator).
+        const std::size_t document_start = chars_read - sizeof(std::int32_t);
+        const std::size_t expected_end = document_start + static_cast<std::size_t>(document_size);
 
         if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))
         {
@@ -10576,7 +10580,10 @@
     bool parse_bson_array()
     {
         std::int32_t document_size{};
-        get_number<std::int32_t, true>(input_format_t::bson, document_size);
+        if (JSON_HEDLEY_UNLIKELY((!get_number<std::int32_t, true>(input_format_t::bson, document_size))))
+        {
+            return false;
+        }
 
         if (JSON_HEDLEY_UNLIKELY(document_size < 5))
         {
@@ -10587,9 +10594,10 @@
                                             "document size"), nullptr));
         }
 
-        // chars_read now points just past the 4-byte size field;
-        // the document started 4 bytes earlier and must end at start + document_size.
-        const std::size_t expected_end = chars_read + static_cast<std::size_t>(document_size) - 4;
+        // The document begins at the size field and ends document_size bytes later
+        // (including the size field itself and the trailing 0x00 terminator).
+        const std::size_t document_start = chars_read - sizeof(std::int32_t);
+        const std::size_t expected_end = document_start + static_cast<std::size_t>(document_size);
 
         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 b5cd004..53c308a 100644
--- a/tests/src/unit-bson.cpp
+++ b/tests/src/unit-bson.cpp
@@ -1302,6 +1302,7 @@
         std::vector<std::uint8_t> const v = {0x04, 0x00, 0x00, 0x00, 0x00};
         json _;
         CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 4: syntax error while parsing BSON document size: BSON document size must be at least 5, is 4", json::parse_error&);
+        CHECK(json::from_bson(v, true, false).is_discarded());
     }
 
     SECTION("declared document size must match consumed bytes (extra trailing element)")
@@ -1316,6 +1317,38 @@
         };
         json _;
         CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 16: syntax error while parsing BSON document: BSON document terminator did not land at declared document size", json::parse_error&);
+        CHECK(json::from_bson(v, true, false).is_discarded());
+    }
+
+    SECTION("declared document size must match consumed bytes (premature terminator)")
+    {
+        // Declares 32-byte document but only contains the size field followed by an immediate terminator.
+        std::vector<std::uint8_t> const v =
+        {
+            0x20, 0x00, 0x00, 0x00,
+            0x00
+        };
+        json _;
+        CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 5: syntax error while parsing BSON document: BSON document terminator did not land at declared document size", json::parse_error&);
+        CHECK(json::from_bson(v, true, false).is_discarded());
+    }
+
+    SECTION("array declared size must match consumed bytes")
+    {
+        // Outer object contains an array "a" that declares 5 bytes (empty) but
+        // actually contains an int32 element before its terminator.
+        std::vector<std::uint8_t> const v =
+        {
+            0x14, 0x00, 0x00, 0x00,                         // object size = 20
+            0x04, 'a', 0x00,                                // key "a", array type
+            0x05, 0x00, 0x00, 0x00,                         // array declared size = 5 (empty)
+            0x10, '0', 0x00, 0x01, 0x00, 0x00, 0x00,        // extra int32 element "0" = 1
+            0x00,                                           // array terminator
+            0x00                                            // object terminator
+        };
+        json _;
+        CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 19: syntax error while parsing BSON document: BSON document terminator did not land at declared document size", json::parse_error&);
+        CHECK(json::from_bson(v, true, false).is_discarded());
     }
 
     SECTION("BSON string must end with 0x00")
@@ -1331,5 +1364,6 @@
         };
         json _;
         CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 13: syntax error while parsing BSON string: BSON string is not null-terminated", json::parse_error&);
+        CHECK(json::from_bson(v, true, false).is_discarded());
     }
-}
\ No newline at end of file
+}