From 5a6050210da1cfe579fe00714261067d7e00c496 Mon Sep 17 00:00:00 2001 From: leftibot Date: Sun, 12 Apr 2026 16:39:19 -0600 Subject: [PATCH] Fix #594: Map keys become dangling references when pushed into Vector (#650) The Handle_Return_Ref specialization for const references was wrapping return values in std::cref() while marking them as return values (is_return_value=true). This caused Vector.push_back() to store the reference directly without cloning, since it assumes return values are freshly created temporaries. When the source object (e.g., a map) went out of scope, the vector contained dangling references to freed memory. The fix sets is_return_value=false for const reference returns, which correctly triggers push_back to clone the value instead of storing a bare reference. This is consistent with the non-const reference handler (Handle_Return) which also does not set the return value flag. Co-authored-by: leftibot Co-authored-by: Claude Opus 4.6 (1M context) --- .../chaiscript/dispatchkit/handle_return.hpp | 2 +- unittests/map_keys_vector_push_back.chai | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 unittests/map_keys_vector_push_back.chai diff --git a/include/chaiscript/dispatchkit/handle_return.hpp b/include/chaiscript/dispatchkit/handle_return.hpp index e0a3b132..e0d4e3ae 100644 --- a/include/chaiscript/dispatchkit/handle_return.hpp +++ b/include/chaiscript/dispatchkit/handle_return.hpp @@ -126,7 +126,7 @@ namespace chaiscript { struct Handle_Return_Ref { template static Boxed_Value handle(T &&r) { - return Boxed_Value(std::cref(r), true); + return Boxed_Value(std::cref(r), false); } }; diff --git a/unittests/map_keys_vector_push_back.chai b/unittests/map_keys_vector_push_back.chai new file mode 100644 index 00000000..2310e846 --- /dev/null +++ b/unittests/map_keys_vector_push_back.chai @@ -0,0 +1,29 @@ +// Regression test for issue #594 +// Map keys pushed into a vector via .first should remain valid +// after the map goes out of scope. + +def keys(Map map) +{ + var v = Vector(); + for( i : map ) + { + v.push_back(i.first); + } + return v; +} + +var k = Vector(); +if ( true ) +{ + var m = ["a":"x", "b":"y", "c":"z"]; + k = keys(m); +} + +// After the map is out of scope, the keys should still be valid strings +assert_equal(3, k.size()) + +// Verify each element is a non-empty string +for (elem : k) +{ + assert_true(elem.size() > 0) +}