mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-07-30 16:26:28 +08:00
Fix #635: Segfault in async result via dangling pointer from optimized for loop
Two bugs combined to cause the crash: 1. The optimized for loop (chaiscript_optimizer.hpp) stored the loop counter as a stack-local `int` and exposed it to ChaiScript via `var(&i)`, creating a reference-type Boxed_Value pointing to the stack frame. 2. The `:=` operator's `Data::operator=` performed a shallow clone of the Any (copying the reference_wrapper, not the value), so `ret := i` made `ret` alias the stack-local `int`. When the optimized loop's frame unwound, `ret` held a dangling pointer. Fix 1: The optimizer now heap-allocates the loop counter via `Boxed_Value(start_int)` and obtains a reference to the heap-allocated int for the native C++ loop. The Boxed_Value's shared_ptr ensures the storage outlives any copies. Fix 2: The `:=` operator now deep-copies arithmetic values via `Boxed_Number::clone` instead of the shallow `assign()`, ensuring value semantics. This also fixes a pre-existing aliasing bug where `a := b; ++b` would incorrectly mutate `a`. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4804fb6e03
commit
6dc28ca1ba
@ -473,7 +473,11 @@ namespace chaiscript {
|
||||
}
|
||||
} else if (this->text == ":=") {
|
||||
if (params[0].is_undef() || Boxed_Value::type_match(params[0], params[1])) {
|
||||
params[0].assign(params[1]);
|
||||
if (params[1].get_type_info().is_arithmetic() && params[0].get_type_info().is_arithmetic()) {
|
||||
params[0].assign(Boxed_Number::clone(params[1]));
|
||||
} else {
|
||||
params[0].assign(params[1]);
|
||||
}
|
||||
params[0].reset_return_value();
|
||||
} else {
|
||||
throw exception::eval_error("Mismatched types in equation");
|
||||
|
||||
@ -397,8 +397,9 @@ namespace chaiscript {
|
||||
assert(children.size() == 1);
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
|
||||
int i = start_int;
|
||||
t_ss.add_object(id, var(&i));
|
||||
Boxed_Value bv_i(start_int);
|
||||
auto &i = *static_cast<int *>(bv_i.get_ptr());
|
||||
t_ss.add_object(id, bv_i);
|
||||
|
||||
try {
|
||||
for (; i < end_int; ++i) {
|
||||
|
||||
7
unittests/assign_no_aliasing.chai
Normal file
7
unittests/assign_no_aliasing.chai
Normal file
@ -0,0 +1,7 @@
|
||||
// Verify that := performs a value copy, not an alias
|
||||
var a = 10
|
||||
var b = 20
|
||||
a := b
|
||||
++b
|
||||
assert_equal(20, a)
|
||||
assert_equal(21, b)
|
||||
13
unittests/async_return_value.chai
Normal file
13
unittests/async_return_value.chai
Normal file
@ -0,0 +1,13 @@
|
||||
var func = fun(){
|
||||
var ret = 0;
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
ret := i;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
var&fut1 = async(func);
|
||||
var fut2 = async(func);
|
||||
|
||||
assert_equal(999, fut1.get())
|
||||
assert_equal(999, fut2.get())
|
||||
Loading…
x
Reference in New Issue
Block a user