mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-07-31 00:37:02 +08:00
Fix #635: Segfault in optimized for-loop when := copies stack-local variable
The optimized for-loop in chaiscript_optimizer.hpp stored the loop counter as a stack-local int and exposed it to ChaiScript via var(&i), creating a reference. When the := operator was used inside the loop body (e.g. ret := i), it copied the raw pointers to this stack variable into the target's Data. When the function returned via exception unwinding, the stack frame was destroyed, leaving dangling pointers in the return value. Accessing these pointers in the caller (e.g. via string interpolation) caused a segfault. The fix heap-allocates the loop counter via std::make_shared<int>, so the data survives scope exit through reference counting. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7b45fe19fe
commit
f1a0c2ae41
@ -397,11 +397,11 @@ 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));
|
||||
auto i = std::make_shared<int>(start_int);
|
||||
t_ss.add_object(id, var(i));
|
||||
|
||||
try {
|
||||
for (; i < end_int; ++i) {
|
||||
for (; *i < end_int; ++(*i)) {
|
||||
try {
|
||||
// Body of Loop
|
||||
children[0]->eval(t_ss);
|
||||
|
||||
21
unittests/future_assign.chai
Normal file
21
unittests/future_assign.chai
Normal file
@ -0,0 +1,21 @@
|
||||
// Regression test for #635: Segfault when using := in async function
|
||||
// with optimized for loop. The := operator copies raw pointers from the
|
||||
// loop variable, which is stack-allocated in the optimized for loop.
|
||||
// When the function returns, the stack is unwound and pointers dangle.
|
||||
|
||||
var func = fun(){
|
||||
var ret = 0;
|
||||
for (var i = 0; i < 50000; ++i) {
|
||||
ret := i;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
var fut1 = async(func);
|
||||
var fut2 = async(func);
|
||||
|
||||
// This triggers Boxed_Number::get_as<int> on the future results
|
||||
// which would crash if the pointers are dangling
|
||||
// := creates an alias, so ret ends up as 50000 (loop exit value of i)
|
||||
assert_equal(50000, fut1.get())
|
||||
assert_equal(50000, fut2.get())
|
||||
Loading…
x
Reference in New Issue
Block a user