mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-08 08:44:37 +08:00
Node islands: read the stack from the frame address, strip ASan's swapcontext warning, fix a race in 6811
- ni_stack_limit classifies the stack by the frame address. Under ASan's use-after-return detection a local lives on a fake stack, so a call into Node from a hosted promise reaction got the wrong V8 stack limit and hit "Maximum call stack size exceeded" (6802, dev, sanitized). - The ordering harness drops ASan's once-per-process makecontext/swapcontext warning from stderr, as the other harnesses do. - 6811's island timers fire at 15 and 40 ms, after the program's immediate and its 5 and 10 ms timers, instead of racing the first loop turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
eaefbdf44f
commit
049b34c166
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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<string> {
|
||||
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}]`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user