mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-04-30 19:09:26 +08:00
* Fix #635: Segfault in async result via dangling pointer from optimized for loop * 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.
This commit is contained in:
parent
5a6050210d
commit
07d62aae99
@ -295,6 +295,7 @@ list(SORT UNIT_TESTS)
|
||||
if(NOT MULTITHREAD_SUPPORT_ENABLED)
|
||||
list(REMOVE_ITEM UNIT_TESTS
|
||||
async_engine_lifetime.chai
|
||||
async_return_value.chai
|
||||
future.chai
|
||||
list_push_front.chai
|
||||
move_async.chai
|
||||
|
||||
@ -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) {
|
||||
|
||||
41
unittests/assign_no_aliasing.chai
Normal file
41
unittests/assign_no_aliasing.chai
Normal file
@ -0,0 +1,41 @@
|
||||
// Issue #635: optimized for loop with := must not produce dangling values
|
||||
// := is reference-assign, so ret aliases i and sees the loop exit value
|
||||
|
||||
// Basic: capture loop variable via :=
|
||||
var ret = 0
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
ret := i
|
||||
}
|
||||
assert_equal(100, ret)
|
||||
|
||||
// Return from function containing optimized for loop
|
||||
def loop_result() {
|
||||
var ret = 0
|
||||
for (var i = 0; i < 200; ++i) {
|
||||
ret := i
|
||||
}
|
||||
return ret
|
||||
}
|
||||
assert_equal(200, loop_result())
|
||||
|
||||
// Multiple calls return consistent results
|
||||
assert_equal(loop_result(), loop_result())
|
||||
|
||||
// Nested optimized for loops
|
||||
var outer_val = 0
|
||||
var inner_val = 0
|
||||
for (var i = 0; i < 10; ++i) {
|
||||
for (var j = 0; j < 10; ++j) {
|
||||
inner_val := j
|
||||
}
|
||||
outer_val := i
|
||||
}
|
||||
assert_equal(10, outer_val)
|
||||
assert_equal(10, inner_val)
|
||||
|
||||
// Value-assign (=) captures last body-iteration value, not exit value
|
||||
var ret2 = 0
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
ret2 = i
|
||||
}
|
||||
assert_equal(99, ret2)
|
||||
25
unittests/async_return_value.chai
Normal file
25
unittests/async_return_value.chai
Normal file
@ -0,0 +1,25 @@
|
||||
// Issue #635: async + optimized for loop must not segfault from dangling pointer
|
||||
// := is reference-assign, so ret aliases i and sees the loop exit value
|
||||
|
||||
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(1000, fut1.get())
|
||||
assert_equal(1000, fut2.get())
|
||||
|
||||
// Multiple concurrent async calls to stress the scenario
|
||||
var results = []
|
||||
for (var n = 0; n < 5; ++n) {
|
||||
results.push_back(async(func))
|
||||
}
|
||||
for (var n = 0; n < 5; ++n) {
|
||||
assert_equal(1000, results[n].get())
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user