diff --git a/include/boost/json/impl/pointer.ipp b/include/boost/json/impl/pointer.ipp index a6a05d84d..897c896ef 100644 --- a/include/boost/json/impl/pointer.ipp +++ b/include/boost/json/impl/pointer.ipp @@ -426,6 +426,11 @@ value::set_at_pointer( system::error_code& ec, set_pointer_options const& opts ) { + // ref can refer to an element of this document, which the walk below + // can replace or relocate while it creates missing elements, so the new + // value is created before the document is modified + value new_value = ref.make_value( storage() ); + value* result = detail::walk_pointer( *this, sv, @@ -495,7 +500,7 @@ value::set_at_pointer( }); if( result ) - *result = ref.make_value( storage() ); + *result = std::move(new_value); return result; } diff --git a/test/pointer.cpp b/test/pointer.cpp index 7a2ffcbb8..75f56dcda 100644 --- a/test/pointer.cpp +++ b/test/pointer.cpp @@ -340,6 +340,14 @@ class pointer_test BOOST_TEST(( jv == object{ {"x", 1} } )); BOOST_TEST( *result == 1 ); BOOST_TEST( result == &jv.at_pointer("/x") ); + + // the new value has to be created before the walk, because the walk + // replaces and reallocates elements the value_ref can refer to + opts = {}; + jv = object{ {"c", nullptr} }; + result = &jv.set_at_pointer( "/c/x", jv.at("c"), opts ); + BOOST_TEST(( jv == object{ {"c", object{ {"x", nullptr} }} } )); + BOOST_TEST( result == &jv.at_pointer("/c/x") ); } template