mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-04-30 19:09:26 +08:00
* Fix #655: Join async threads before engine destruction to prevent heap-use-after-free Issues #632 and #636 (PRs #651 and #653) both stem from the same root cause: async threads spawned via async() can outlive the Dispatch_Engine, accessing shared state (global objects map, type maps) after it has been destroyed. The fix moves async() registration from the stdlib module into ChaiScript_Basic, where spawned threads are tracked via Dispatch_Engine. The engine's destructor now joins all outstanding async threads before destroying shared data structures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Address review: follow rule of 5, explicitly default move operations Requested by @lefticus in PR #656 review. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: leftibot <leftibot@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
47 lines
1.2 KiB
C++
47 lines
1.2 KiB
C++
// Regression test for #632 and #636:
|
|
// Heap-use-after-free when async threads outlive the ChaiScript engine.
|
|
// The engine must join all outstanding async threads before destroying shared state.
|
|
|
|
#include <chaiscript/chaiscript.hpp>
|
|
|
|
int main() {
|
|
// Test 1: Async threads still running when engine is destroyed.
|
|
// Without the fix, this triggers heap-use-after-free under ASAN/TSAN.
|
|
for (int iter = 0; iter < 3; ++iter) {
|
|
{
|
|
chaiscript::ChaiScript chai;
|
|
try {
|
|
chai.eval(R"(
|
|
var func = fun(){
|
|
var ret = 0;
|
|
for (var i = 0; i < 5000; ++i) {
|
|
ret += i;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
var fut1 = async(func);
|
|
var fut2 = async(func);
|
|
)");
|
|
// Engine destroyed here without waiting for futures.
|
|
} catch (const std::exception &) {
|
|
// Exceptions are fine
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test 2: Verify async still works correctly (results are accessible).
|
|
{
|
|
chaiscript::ChaiScript chai;
|
|
auto result = chai.eval<int>(R"(
|
|
var f = async(fun() { return 42; });
|
|
f.get();
|
|
)");
|
|
if (result != 42) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|