JS_FreeRuntime assertion fails after OOM with persistent objects
Version: quickjs-emscripten@0.32.0
Description
Calling ctx.dispose() after an OOM exception crashes the process with a WASM abort when the VM has any persistent heap objects (arrays, plain objects, etc.).
Assertion failed: list_empty(&rt->gc_obj_list), at: ../../vendor/quickjs/quickjs.c,2036,JS_FreeRuntime
This regression was introduced in 0.32.0. The same code works correctly in 0.31.0.
Minimal Reproduction
import { getQuickJS } from "quickjs-emscripten";
const ctx = (await getQuickJS()).newContext();
ctx.runtime.setMemoryLimit(200 * 1024);
// Any persistent VM object triggers the issue
ctx.evalCode(`var arr = [];`);
// Trigger OOM
try {
ctx.evalCode(`for (let i = 0; i < 1e6; i++) { arr.push("x".repeat(100)); }`);
} catch (e) {}
ctx.runtime.setMemoryLimit(-1); // Removing the limit does not help
ctx.dispose(); // 💥 Aborted: Assertion failed: list_empty(&rt->gc_obj_list)
### Expected Behavior
ctx.dispose() completes cleanly after an OOM exception is caught.
Actual Behavior
WASM Abort:
Assertion failed: list_empty(&rt->gc_obj_list), at: ../../vendor/quickjs/quickjs.c,2036,JS_FreeRuntime
Notes
- Works correctly in quickjs-emscripten@0.31.0
- The assertion list_empty(&rt->gc_obj_list) was added to JS_FreeRuntime in QuickJS 2025-09-13
- OOM appears to leave some objects in an inconsistent state that prevents JS_FreeContext's cascade-free from completing before the runtime is torn down
- Removing the memory limit before ctx.dispose() does not resolve the crash
- Plain OOM with only transient (stack-local) objects does not trigger the crash — a persistent global variable is required to reproduce
Environment
- quickjs-emscripten: 0.32.0
- Node.js: v25.8.0
- Platform: macOS (darwin)
JS_FreeRuntimeassertion fails after OOM with persistent objectsVersion:
quickjs-emscripten@0.32.0Description
Calling
ctx.dispose()after an OOM exception crashes the process with a WASM abort when the VM has any persistent heap objects (arrays, plain objects, etc.).This regression was introduced in
0.32.0. The same code works correctly in0.31.0.Minimal Reproduction
Actual Behavior
WASM Abort:
Notes
Environment