diff --git a/src/jsc/bindings/c-bindings.cpp b/src/jsc/bindings/c-bindings.cpp index a20749bef69..1b42f7dc364 100644 --- a/src/jsc/bindings/c-bindings.cpp +++ b/src/jsc/bindings/c-bindings.cpp @@ -933,9 +933,11 @@ static struct sigaction previous_actions[NSIG]; M(SIGIO); #if OS(LINUX) +// SIGPWR is intentionally excluded: JSC uses it for GC thread suspend/resume +// on Linux (see WTF/wtf/posix/ThreadingPOSIX.cpp). Replacing that handler here +// makes the next GC-sent SIGPWR terminate the process. #define FOR_EACH_LINUX_ONLY_SIGNAL(M) \ M(SIGPOLL); \ - M(SIGPWR); \ M(SIGSTKFLT); #endif diff --git a/src/jsc/bindings/wtf-bindings.cpp b/src/jsc/bindings/wtf-bindings.cpp index 0d4968f805f..8b09b5a8665 100644 --- a/src/jsc/bindings/wtf-bindings.cpp +++ b/src/jsc/bindings/wtf-bindings.cpp @@ -61,7 +61,7 @@ extern "C" int uv_tty_reset_mode(void) static void uv__tty_make_raw(struct termios* tio) { - assert(tio != NULL); + ASSERT(tio != NULL); #if defined __sun || defined __MVS__ /* diff --git a/test/js/bun/spawn/spawnSync.test.ts b/test/js/bun/spawn/spawnSync.test.ts index bb60b9cad9e..701413ba817 100644 --- a/test/js/bun/spawn/spawnSync.test.ts +++ b/test/js/bun/spawn/spawnSync.test.ts @@ -40,4 +40,31 @@ describe("spawnSync", () => { it.skipIf(!isPosix)("should use spawnSync optimizations when possible", () => { expect([join(import.meta.dir, "spawnSync-counters-fixture.ts")]).toRun(); }); + + // On Linux, JSC uses SIGPWR to suspend/resume threads for GC. The spawnSync + // signal-forwarding table used to include SIGPWR, so a GC that fired while + // (or after) spawnSync ran would terminate the process with signal 30. + it.skipIf(process.platform !== "linux")("does not clobber the GC thread-suspend signal handler", () => { + const result = Bun.spawnSync({ + cmd: [ + bunExe(), + "-e", + ` + for (let i = 0; i < 50; i++) { + Bun.spawnSync({ cmd: ["true"] }); + Bun.gc(true); + } + for (let i = 0; i < 50; i++) { + Bun.spawnSync({ cmd: ["true"] }); + } + Bun.gc(true); + `, + ], + env: bunEnv, + stdout: "inherit", + stderr: "inherit", + }); + expect(result.signalCode).toBeFalsy(); + expect(result.exitCode).toBe(0); + }); });