From d46c80b983200ef1a7a0b7db497eaef39c17d233 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 10 Sep 2026 18:43:09 +0200 Subject: [PATCH] Make the UBJSON/BJData advance loop's top a copy, not a reference Same issue as the CBOR reader: top aliased container_stack.back() and was read (top.is_object) right after container_stack.pop_back() ended its lifetime. A copy stays valid regardless of what happens to the stack; the one place that mutates the live entry (--top.remaining) now goes through container_stack.back() directly. Signed-off-by: Niels Lohmann --- include/nlohmann/detail/input/binary_reader.hpp | 12 ++++++------ single_include/nlohmann/json.hpp | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 40fb6d207..4295bf229 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -2205,17 +2205,18 @@ class binary_reader } // advance to the next element, closing the containers that ended. - // The reference is not held across get_ubjson_value() above, which - // can push onto the stack and reallocate it. + // top is a copy, not a reference: it must stay valid across the + // pop_back() below, which destroys the container_stack element it + // would otherwise alias. for (;;) { - container_frame& top = container_stack.back(); + container_frame top = container_stack.back(); if (top.remaining != npos) { if (top.remaining != 0) { - --top.remaining; + --container_stack.back().remaining; if (top.is_object) { key.clear(); @@ -2254,9 +2255,8 @@ class binary_reader break; } - const bool is_object = top.is_object; container_stack.pop_back(); - if (JSON_HEDLEY_UNLIKELY(is_object ? !sax->end_object() : !sax->end_array())) + if (JSON_HEDLEY_UNLIKELY(top.is_object ? !sax->end_object() : !sax->end_array())) { return false; } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 8199ff107..1d91e94f1 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -13029,17 +13029,18 @@ class binary_reader } // advance to the next element, closing the containers that ended. - // The reference is not held across get_ubjson_value() above, which - // can push onto the stack and reallocate it. + // top is a copy, not a reference: it must stay valid across the + // pop_back() below, which destroys the container_stack element it + // would otherwise alias. for (;;) { - container_frame& top = container_stack.back(); + container_frame top = container_stack.back(); if (top.remaining != npos) { if (top.remaining != 0) { - --top.remaining; + --container_stack.back().remaining; if (top.is_object) { key.clear(); @@ -13078,9 +13079,8 @@ class binary_reader break; } - const bool is_object = top.is_object; container_stack.pop_back(); - if (JSON_HEDLEY_UNLIKELY(is_object ? !sax->end_object() : !sax->end_array())) + if (JSON_HEDLEY_UNLIKELY(top.is_object ? !sax->end_object() : !sax->end_array())) { return false; }