From 66877675b1fca34f009b3f11db786ef62c5071c7 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 30 Sep 2026 20:07:52 +0200 Subject: [PATCH] Check the iterator range for binary values in basic_json(first, last) (#5719) basic_json(first, last) treated value_t::binary like the structured types (array, object) in the range check, so it always copied the whole binary value regardless of the iterators, even for an empty range such as (b.end(), b.end()). The other primitive types (number, boolean, string) already reject such a range with invalid_iterator.204, and erase(first, last) already does the same for binary values, so this made the constructor inconsistent with both. Move case value_t::binary into the group of checked primitive types. Also update the two matching passages in basic_json.md that describe overload 7, and add a version-history note. Fixes #5670. Signed-off-by: Niels Lohmann --- docs/mkdocs/docs/api/basic_json/basic_json.md | 12 +++++++----- include/nlohmann/json.hpp | 2 +- single_include/nlohmann/json.hpp | 2 +- tests/src/unit-constructor1.cpp | 14 ++++++++++++++ 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/docs/mkdocs/docs/api/basic_json/basic_json.md b/docs/mkdocs/docs/api/basic_json/basic_json.md index 6aaab23c9..3a7a6eb8b 100644 --- a/docs/mkdocs/docs/api/basic_json/basic_json.md +++ b/docs/mkdocs/docs/api/basic_json/basic_json.md @@ -139,8 +139,8 @@ basic_json(basic_json&& other) noexcept; - In case of a `#!json null` type, [invalid_iterator.206](../../home/exceptions.md#jsonexceptioninvalid_iterator206) is thrown. - - In case of other primitive types (number, boolean, or string), `first` must be `begin()` and `last` must be - `end()`. In this case, the value is copied. Otherwise, + - In case of other primitive types (number, boolean, string, or binary), `first` must be `begin()` and `last` + must be `end()`. In this case, the value is copied. Otherwise, [`invalid_iterator.204`](../../home/exceptions.md#jsonexceptioninvalid_iterator204) is thrown. - In case of structured types (array, object), the constructor behaves as similar versions for `std::vector` or `std::map`; that is, a JSON array or object is constructed from the values in the range. @@ -242,8 +242,8 @@ basic_json(basic_json&& other) noexcept; and `last` are not compatible (i.e., do not belong to the same JSON value). In this case, the range `[first, last)` is undefined. - Throws [`invalid_iterator.204`](../../home/exceptions.md#jsonexceptioninvalid_iterator204) if iterators `first` - and `last` belong to a primitive type (number, boolean, or string), but `first` does not point to the first - element anymore. In this case, the range `[first, last)` is undefined. See the example code below. + and `last` belong to a primitive type (number, boolean, string, or binary), but `first` does not point to the + first element anymore. In this case, the range `[first, last)` is undefined. See the example code below. - Throws [`invalid_iterator.206`](../../home/exceptions.md#jsonexceptioninvalid_iterator206) if iterators `first` and `last` belong to a `#!json null` value. In this case, the range `[first, last)` is undefined. 8. (none) @@ -423,6 +423,8 @@ basic_json(basic_json&& other) noexcept; 4. Since version 3.2.0. 5. Since version 1.0.0. 6. Since version 1.0.0. -7. Since version 1.0.0. +7. Since version 1.0.0. Fixed in version 3.13.0 to also check the iterator range for binary values; before, a range + that did not cover the whole value (such as `(end(), end())`) was accepted and the whole binary value was copied, + unlike the other primitive types. 8. Since version 1.0.0. 9. Since version 1.0.0. diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index f394af567..cd731c290 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1827,6 +1827,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case value_t::number_integer: case value_t::number_unsigned: case value_t::string: + case value_t::binary: { if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() || !last.m_it.primitive_iterator.is_end())) @@ -1839,7 +1840,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case value_t::null: case value_t::object: case value_t::array: - case value_t::binary: case value_t::discarded: default: break; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 5a4595956..c54656207 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -28756,6 +28756,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case value_t::number_integer: case value_t::number_unsigned: case value_t::string: + case value_t::binary: { if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() || !last.m_it.primitive_iterator.is_end())) @@ -28768,7 +28769,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case value_t::null: case value_t::object: case value_t::array: - case value_t::binary: case value_t::discarded: default: break; diff --git a/tests/src/unit-constructor1.cpp b/tests/src/unit-constructor1.cpp index 631d1a212..600eb0069 100644 --- a/tests/src/unit-constructor1.cpp +++ b/tests/src/unit-constructor1.cpp @@ -1648,6 +1648,20 @@ TEST_CASE("constructors") CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); } } + + SECTION("binary") + { + { + json j = json::binary({1, 2, 3}); + CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); + CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); + } + { + json const j = json::binary({1, 2, 3}); + CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); + CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); + } + } } } }