diff --git a/packages/runtime/src/scr_node_island.c b/packages/runtime/src/scr_node_island.c index 22a9d6a91f..2504e9c966 100644 --- a/packages/runtime/src/scr_node_island.c +++ b/packages/runtime/src/scr_node_island.c @@ -336,8 +336,9 @@ static void ni_call_job(void *p) { * runtime's guard for it: its mapping's start plus the reserve compiled * code keeps). */ static uintptr_t ni_stack_limit(void) { - char here; - uintptr_t sp = (uintptr_t)&here; + /* The frame address, not a local's: under ASan's use-after-return + * detection locals live on a fake stack elsewhere in memory. */ + uintptr_t sp = (uintptr_t)__builtin_frame_address(0); if (ni_stack != NULL && sp > (uintptr_t)ni_stack && sp <= (uintptr_t)ni_stack + NI_STACK) return (uintptr_t)(ni_stack + NI_GUARD) + NI_STACK / 8; if (sp > ni_main_lo && sp <= ni_main_hi) { diff --git a/tests/corpus/6811-node-island-uncaught-listener/island.cjs b/tests/corpus/6811-node-island-uncaught-listener/island.cjs index 6cb97bed47..650c7f3f35 100644 --- a/tests/corpus/6811-node-island-uncaught-listener/island.cjs +++ b/tests/corpus/6811-node-island-uncaught-listener/island.cjs @@ -1,4 +1,4 @@ exports.timers = () => { - setTimeout(() => console.log("island timer 1"), 1); - setTimeout(() => console.log("island timer 2"), 20); + setTimeout(() => console.log("island timer 1"), 15); + setTimeout(() => console.log("island timer 2"), 40); }; diff --git a/tests/harness/node-island-order.test.ts b/tests/harness/node-island-order.test.ts index ce2bd1bef3..8b14050bfd 100644 --- a/tests/harness/node-island-order.test.ts +++ b/tests/harness/node-island-order.test.ts @@ -53,20 +53,26 @@ const programs = existsSync(programsDir) .sort() : []; +/** Linux ASan's once-per-process warning at the first context switch (the + * runtime's fibers and Node's stack): not program output. */ +const ASAN_SWAP = /^==\d+==WARNING: ASan doesn't fully support makecontext\/swapcontext.*\n/gm; + /** One run's observable outcome: stdout, stderr and the exit status. */ async function outcome(cmd: string, args: string[]): Promise { try { - const { stdout, stderr } = await execFileAsync(cmd, args, { + const { stdout, stderr: raw } = await execFileAsync(cmd, args, { cwd: repoRoot, encoding: "utf8", timeout: 20_000, env: { ...process.env, NODE_NO_WARNINGS: "1" }, }); + const stderr = raw.replace(ASAN_SWAP, ""); return `${stdout}${stderr === "" ? "" : `[stderr]\n${stderr}`}[exit 0]`; } catch (err) { const e = err as { stdout?: string; stderr?: string; code?: unknown; signal?: unknown }; if (typeof e.code !== "number") return `[failed ${String(e.signal ?? e.code)}]`; - return `${e.stdout ?? ""}${e.stderr ? `[stderr]\n${e.stderr}` : ""}[exit ${e.code}]`; + const stderr = (e.stderr ?? "").replace(ASAN_SWAP, ""); + return `${e.stdout ?? ""}${stderr ? `[stderr]\n${stderr}` : ""}[exit ${e.code}]`; } }