From c5a7a4b46d91231e3ad3bf5572f0cc165f356379 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 4 Oct 2026 22:11:34 +0200 Subject: [PATCH] Add deprecated from_bon8/from_bjdata(ptr, len) overloads (#5688) from_bon8(ptr, len) and from_bjdata(ptr, len) had no overload for a pointer and a length, unlike from_cbor/from_msgpack/from_ubjson/ from_bson. The call instead bound to from_*(InputType&&, bool strict), which read ptr as a NUL-terminated C string via strlen and silently converted len to the strict flag. Data containing a 0x00 byte was cut off there; data without one was read past the end of the buffer. Add a deprecated (ptr, len, strict, allow_exceptions) overload for each function that forwards to (ptr, ptr + len, ...), matching the existing deprecated overloads of the other four binary readers. Since neither function ever had this overload, the deprecation is declared as of version 3.13.0, the next unreleased version, rather than the version each function was originally added in. Fixes #5648. Signed-off-by: Niels Lohmann --- .../mkdocs/docs/api/basic_json/from_bjdata.md | 9 ++++++ docs/mkdocs/docs/api/basic_json/from_bon8.md | 9 ++++++ include/nlohmann/json.hpp | 20 +++++++++++++ single_include/nlohmann/json.hpp | 20 +++++++++++++ tests/src/unit-bjdata.cpp | 28 +++++++++++++++++++ tests/src/unit-bon8.cpp | 28 +++++++++++++++++++ 6 files changed, 114 insertions(+) diff --git a/docs/mkdocs/docs/api/basic_json/from_bjdata.md b/docs/mkdocs/docs/api/basic_json/from_bjdata.md index a45e00ad5..f19f9e4a9 100644 --- a/docs/mkdocs/docs/api/basic_json/from_bjdata.md +++ b/docs/mkdocs/docs/api/basic_json/from_bjdata.md @@ -120,3 +120,12 @@ Linear in the size of the input. - Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0. - Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0. - Added `error_handler` parameter in version 3.13.0. + +!!! warning "Deprecation" + + - Overload (2) replaces calls to `from_bjdata` with a pointer and a length as first two parameters, which has been + deprecated in version 3.13.0. This overload will be removed in version 4.0.0. Please replace all calls like + `#!cpp from_bjdata(ptr, len, ...);` with `#!cpp from_bjdata(ptr, ptr+len, ...);`. + + You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated + function. diff --git a/docs/mkdocs/docs/api/basic_json/from_bon8.md b/docs/mkdocs/docs/api/basic_json/from_bon8.md index 2f9d1e749..cac6b31eb 100644 --- a/docs/mkdocs/docs/api/basic_json/from_bon8.md +++ b/docs/mkdocs/docs/api/basic_json/from_bon8.md @@ -106,3 +106,12 @@ Linear in the size of the input. ## Version history - Added in version 3.13.0. + +!!! warning "Deprecation" + + - Overload (2) replaces calls to `from_bon8` with a pointer and a length as first two parameters, which has been + deprecated in version 3.13.0. This overload will be removed in version 4.0.0. Please replace all calls like + `#!cpp from_bon8(ptr, len, ...);` with `#!cpp from_bon8(ptr, ptr+len, ...);`. + + You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated + function. diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 3f3645524..ca9682bd5 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -5956,6 +5956,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bjdata, strict, allow_exceptions, error_handler); } + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bjdata(ptr, ptr + len)) + static basic_json from_bjdata(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_bjdata(ptr, ptr + len, strict, allow_exceptions); + } + /// @brief create a JSON value from an input in BON8 format /// @sa https://json.nlohmann.me/api/basic_json/from_bon8/ template @@ -5979,6 +5989,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bon8, strict, allow_exceptions); } + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bon8(ptr, ptr + len)) + static basic_json from_bon8(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_bon8(ptr, ptr + len, strict, allow_exceptions); + } + /// @brief create a JSON value from an input in BSON format /// @sa https://json.nlohmann.me/api/basic_json/from_bson/ template diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index b5e7417e6..ef6f3d26a 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -33078,6 +33078,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bjdata, strict, allow_exceptions, error_handler); } + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bjdata(ptr, ptr + len)) + static basic_json from_bjdata(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_bjdata(ptr, ptr + len, strict, allow_exceptions); + } + /// @brief create a JSON value from an input in BON8 format /// @sa https://json.nlohmann.me/api/basic_json/from_bon8/ template @@ -33101,6 +33111,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bon8, strict, allow_exceptions); } + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bon8(ptr, ptr + len)) + static basic_json from_bon8(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_bon8(ptr, ptr + len, strict, allow_exceptions); + } + /// @brief create a JSON value from an input in BSON format /// @sa https://json.nlohmann.me/api/basic_json/from_bson/ template diff --git a/tests/src/unit-bjdata.cpp b/tests/src/unit-bjdata.cpp index 0098541cf..06646c1d0 100644 --- a/tests/src/unit-bjdata.cpp +++ b/tests/src/unit-bjdata.cpp @@ -4490,3 +4490,31 @@ TEST_CASE("BJData roundtrips" * doctest::skip()) } } } + +TEST_CASE("issue #5648 - from_bjdata(ptr, len) must read len bytes, not treat ptr as a C string") +{ + // to_bjdata() encodes the integer 0 as the two bytes 'i' 0x00 (a BJData + // type marker followed by the value byte 0x00), so the packed data + // below contains a 0x00 byte before its end. + const json j = {{"a", 0}}; + const std::vector packed = json::to_bjdata(j); + bool contains_nul = false; + for (const auto byte : packed) + { + contains_nul |= (byte == 0x00); + } + REQUIRE(contains_nul); + + // before the fix, from_bjdata had no (ptr, len) overload, so this call + // bound to from_bjdata(InputType&&, bool strict) instead: ptr was read + // as a NUL-terminated C string (stopping at the embedded 0x00 byte), and + // len was silently converted to the strict flag. The deprecated + // overload added for this issue forwards to from_bjdata(ptr, ptr + len, + // ...) instead, like from_ubjson's deprecated (ptr, len) overload does. + json result; + CHECK_NOTHROW(result = json::from_bjdata(packed.data(), packed.size())); + CHECK(result == j); + + // len must not collapse into the strict flag either + CHECK(json::from_bjdata(packed.data(), packed.size(), false) == j); +} diff --git a/tests/src/unit-bon8.cpp b/tests/src/unit-bon8.cpp index 491189867..9a9116e12 100644 --- a/tests/src/unit-bon8.cpp +++ b/tests/src/unit-bon8.cpp @@ -1014,6 +1014,34 @@ TEST_CASE("BON8 roundtrips" * doctest::skip()) } } +TEST_CASE("issue #5648 - from_bon8(ptr, len) must read len bytes, not treat ptr as a C string") +{ + // to_bon8() encodes the integer 40 as the two bytes 0xC2 0x00 (a BON8 + // lead byte followed by a continuation byte of 0x00), so the packed data + // below contains a 0x00 byte before its end. + const json j = {{"a", 40}, {"b", "x"}}; + const std::vector packed = json::to_bon8(j); + bool contains_nul = false; + for (const auto byte : packed) + { + contains_nul |= (byte == 0x00); + } + REQUIRE(contains_nul); + + // before the fix, from_bon8 had no (ptr, len) overload, so this call + // bound to from_bon8(InputType&&, bool strict) instead: ptr was read as + // a NUL-terminated C string (stopping at the embedded 0x00 byte), and + // len was silently converted to the strict flag. The deprecated + // overload added for this issue forwards to from_bon8(ptr, ptr + len, + // ...) instead, like from_cbor's deprecated (ptr, len) overload does. + json result; + CHECK_NOTHROW(result = json::from_bon8(packed.data(), packed.size())); + CHECK(result == j); + + // len must not collapse into the strict flag either + CHECK(json::from_bon8(packed.data(), packed.size(), false) == j); +} + #ifdef JSON_HAS_CPP_17 TEST_CASE("BON8 with std::byte") {