Checkpoint before integration and package validation. Assisted-by: SurmAgent:unknown [read] [edit] [bash]
29 lines
1.1 KiB
JavaScript
29 lines
1.1 KiB
JavaScript
import * as std from "qjs:std";
|
|
import { assert } from "./assert.js";
|
|
|
|
// Regression test: a suspended coroutine kept reachable only through its mapped
|
|
// `arguments` object must not be collected.
|
|
//
|
|
// A sloppy function with a simple parameter list that uses `arguments` gets a
|
|
// *mapped* arguments object whose entries are open var_refs pointing into the
|
|
// function's frame. That object is a third var_ref holder (besides closures and
|
|
// object var_ref properties) and must be traced the same way; otherwise a
|
|
// suspended coroutine reachable only via an escaped `arguments` is either freed
|
|
// while still live (use-after-free) or wrongly retained (a leak that trips the
|
|
// gc_obj_list check at runtime teardown).
|
|
|
|
globalThis.leaked = null;
|
|
|
|
const AsyncFunction = (async function () {}).constructor;
|
|
const step = AsyncFunction("a", `
|
|
globalThis.leaked = () => arguments; // escapes, capturing the frame
|
|
const d = Promise.withResolvers();
|
|
await d.promise; // suspend; never resolved
|
|
`);
|
|
step(123);
|
|
|
|
std.gc();
|
|
|
|
// If the frame was wrongly collected this reads freed memory.
|
|
assert(leaked()[0], 123);
|