spawn: don't forward SIGPWR — it's JSC's GC suspend/resume signal on Linux#31145
spawn: don't forward SIGPWR — it's JSC's GC suspend/resume signal on Linux#31145robobun wants to merge 1 commit into
Conversation
…Linux Bun__registerSignalsForForwarding() installs a forwarding handler (with SA_RESETHAND) for a set of signals while a synchronous child process runs. On Linux that set included SIGPWR, but Bun's JSC build uses SIGPWR (wtf/posix/ThreadingPOSIX.cpp, g_wtfConfig.sigThreadSuspendResume) to suspend and resume threads during conservative stack scanning. Bun.openInEditor spawns the editor via the sync-spawn path on a background thread. If the GC ran concurrently, the pthread_kill(SIGPWR) sent to the JS thread was delivered to the forwarding handler instead of signalHandlerSuspendResume — the semaphore was never posted (deadlock), and SA_RESETHAND reverted SIGPWR to SIG_DFL so the next suspend killed the process with signal 30. Drop SIGPWR from the Linux forwarding set and add a regression test.
|
Updated 11:31 AM PT - May 20th, 2026
❌ @robobun, your commit 62b97dd has 9 failures in
🧪 To try this PR locally: bunx bun-pr 31145That installs a local version of the PR into your bun-31145 --bun |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughThis PR fixes signal forwarding in Bun to prevent interference with JSC's garbage collector. On Linux, ChangesSIGPWR Signal Forwarding Fix
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
This PR may be a duplicate of:
🤖 Generated with Claude Code |
|
Duplicate of #30956, which already removes Fuzzer fingerprint |
Fuzzilli found a flaky crash (fingerprint
8f15ef1fddf992a0) where Bun terminates withTERMSIG: 30(SIGPWR) on Linux.Root cause
Bun__registerSignalsForForwarding()installs a forwarding signal handler (withSA_RESETHAND) for a set of signals while a synchronous child process runs, so e.g. aSIGINTsent tobun runreaches the script. On Linux that set was copied from npm and includedSIGPWR.Bun's JSC build uses
SIGPWRas the thread suspend/resume signal for GC conservative stack scanning (seewtf/posix/ThreadingPOSIX.cpp,g_wtfConfig.sigThreadSuspendResume— Bun switched from the upstream defaultSIGUSR1so npm packages can useSIGUSR1).Bun.openInEditorlaunches the editor by callingsync::spawnon a detached thread, which hitsBun__registerSignalsForForwarding(). If the GC runs on the JS thread while that forwarding window is open:Thread::suspend()sendsSIGPWRviapthread_killto the JS thread.signalHandlerSuspendResume, so the suspend/resume semaphore is never posted → the GC spins or deadlocks.SA_RESETHANDresetsSIGPWRtoSIG_DFL.SIGPWR(either the GC retry in the suspend loop or the resume) terminates the process with signal 30.Repro
Before this change, with a
codestub onPATH:hangs or dies with
Power failure15/15 runs under the debug build; 0/15 after.Fix
Drop
SIGPWRfromFOR_EACH_LINUX_ONLY_SIGNAL. There is no reason to forward a power-failure signal to a child script, and Bun must never replace this handler while JSC is live.Adds a Linux-only regression test that puts a stub editor on
PATH, interleavesBun.openInEditorwithBun.gc(true), and asserts the process exits cleanly.