From 79a8c279c0760a412ad21e6b97147372045715e3 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 4 Jul 2026 11:02:30 +0200 Subject: [PATCH] Assert memcpy buffer bounds in the contiguous get_elements fast path Make the "buffers are large enough" reasoning explicit: before the copy, assert that `copied` fits both the caller-provided destination (`wanted` bytes) and the remaining input range (`available` bytes). These hold by construction (`copied = min(wanted, available)`) but were previously only implied; the asserts document the invariant and would catch a future regression that breaks it. Signed-off-by: Niels Lohmann Co-Authored-By: Claude Opus 4.8 --- include/nlohmann/detail/input/input_adapters.hpp | 5 +++++ single_include/nlohmann/json.hpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 090f106de..da483fecb 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -206,6 +206,11 @@ class iterator_input_adapter const std::size_t copied = (std::min)(wanted, available); if (JSON_HEDLEY_LIKELY(copied != 0)) { + // the copy must stay within both buffers: the caller-provided + // destination holds `wanted` bytes and the remaining input range + // holds `available` bytes, and `copied` is the minimum of the two + JSON_ASSERT(copied <= wanted); // does not overrun the destination + JSON_ASSERT(copied <= available); // does not read past the input end // &*current yields the raw address for both raw pointers and // non-pointer contiguous iterators (e.g. std::vector's iterator) std::memcpy(dest, &*current, copied); diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 6f18a1bf5..bcc124f14 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -7038,6 +7038,11 @@ class iterator_input_adapter const std::size_t copied = (std::min)(wanted, available); if (JSON_HEDLEY_LIKELY(copied != 0)) { + // the copy must stay within both buffers: the caller-provided + // destination holds `wanted` bytes and the remaining input range + // holds `available` bytes, and `copied` is the minimum of the two + JSON_ASSERT(copied <= wanted); // does not overrun the destination + JSON_ASSERT(copied <= available); // does not read past the input end // &*current yields the raw address for both raw pointers and // non-pointer contiguous iterators (e.g. std::vector's iterator) std::memcpy(dest, &*current, copied);