-
Notifications
You must be signed in to change notification settings - Fork 5k
Fix event-loop hang when dlopen'd Go/cgo lib coexists with WASM on Linux #31161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
robobun
wants to merge
21
commits into
main
Choose a base branch
from
farm/ebd23fe3/fix-31158-sigpwr-sa-onstack
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
76a38f7
ffi: clear SA_ONSTACK on SIGPWR after dlopen
robobun efe6944
[autofix.ci] apply automated fixes
autofix-ci[bot] 44ba51c
comment why Bun__repairJscGcSignalAfterDlopen exists
robobun 05c79cc
drop the watchdog setTimeout — await-using + test timeout cover it
robobun 0ef5a49
[autofix.ci] apply automated fixes
autofix-ci[bot] ce6f4c1
ship the real fix from WebKit#235, drop the band-aid
robobun c0c0e6c
Merge remote-tracking branch 'origin/main' into farm/ebd23fe3/fix-311…
robobun be86d91
ci: retrigger — WebKit #235 preview autobuild is now published
robobun 14c08e5
Merge remote-tracking branch 'origin/main' into farm/ebd23fe3/fix-311…
robobun ee62500
Merge remote-tracking branch 'origin/main' into farm/ebd23fe3/fix-311…
robobun a42d8e1
Merge remote-tracking branch 'origin/main' into farm/ebd23fe3/fix-311…
robobun 5700893
Merge remote-tracking branch 'origin/main' into farm/ebd23fe3/fix-311…
robobun 008c293
Merge remote-tracking branch 'origin/main' into farm/ebd23fe3/fix-311…
robobun 000610a
build: point WEBKIT_VERSION at rebased oven-sh/WebKit#235 preview (66…
robobun 1f4deae
Merge remote-tracking branch 'origin/main' into farm/ebd23fe3/fix-311…
robobun 152f661
Merge remote-tracking branch 'origin/main' into farm/ebd23fe3/fix-311…
robobun 0968c00
build: align WEBKIT_VERSION to WebKit#235 697e8a79 (comment fix)
robobun 7a95440
test(31158): filter benign ASAN stderr banner before asserting
robobun e8111d1
ci: retrigger (WebKit#235 preview tarball autobuild-preview-pr-235-69…
robobun 8a95f9b
Merge remote-tracking branch 'origin/main' into farm/ebd23fe3/fix-311…
robobun 63e2247
Merge remote-tracking branch 'origin/main' into farm/ebd23fe3/fix-311…
robobun File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| // Regression test for https://github.com/oven-sh/bun/issues/31158. | ||
| // | ||
| // When a shared library (e.g. Go's cgo runtime) force-sets `SA_ONSTACK` on | ||
| // JavaScriptCore's thread-suspend signal (SIGPWR on Linux in Bun's WebKit | ||
| // fork), every delivery of that signal on a thread that has an alternate | ||
| // signal stack (ASAN runtime, Bun's crash handler, libbacktrace) runs the | ||
| // handler on the alt stack. WTF's stack-check in `signalHandlerSuspendResume` | ||
| // used `currentStackPointer()` — the handler's own SP — so the sanity | ||
| // check failed every time, `Thread::suspend()` retried forever, and the | ||
| // event loop stopped advancing on the next WASM compile/install. | ||
| // | ||
| // Triggers the exact shape of the bug without needing Go installed in CI: | ||
| // force `SA_ONSTACK` onto SIGPWR via `bun:ffi`, then call `dlopen` once | ||
| // more so the repair fires, then compile+call a WASM function (which | ||
| // triggers `resetInstructionCacheOnAllThreads`). Without the fix, | ||
| // `setTimeout` after the WASM call never fires and the child hangs. | ||
| import { expect, test } from "bun:test"; | ||
| import { bunEnv, bunExe, isGlibc } from "harness"; | ||
|
|
||
| // The bug is only reachable on Linux: SIGPWR is only used as the suspend/ | ||
| // resume signal on Linux (see `vendor/WebKit/Source/WTF/wtf/posix/ | ||
| // ThreadingPOSIX.cpp` — USE(BUN_JSC_ADDITIONS) branch). The reproduction | ||
| // dlopens `libc.so.6` directly so it needs glibc; musl names its libc | ||
| // differently and static-musl builds of Bun don't even have a dynamic | ||
| // loader in the room. | ||
| test.skipIf(!isGlibc)("event loop survives SA_ONSTACK on SIGPWR + WASM (oven-sh/bun#31158)", async () => { | ||
| const script = /* ts */ ` | ||
| import { dlopen, FFIType, ptr } from "bun:ffi"; | ||
|
|
||
| // 1. Open libc so we can flip SA_ONSTACK on SIGPWR the same way Go's | ||
| // cgo 'initsig' does on every inherited handler. | ||
| const libc = dlopen("libc.so.6", { | ||
| sigaction: { args: [FFIType.i32, FFIType.ptr, FFIType.ptr], returns: FFIType.i32 }, | ||
| }); | ||
|
|
||
| // x86_64 glibc layout: sa_handler (8), sa_mask (128), sa_flags (4), sa_restorer (8). | ||
| // We only touch sa_flags so this layout holds on aarch64 too (same offsets). | ||
| const SIGACTION_SIZE = 152; | ||
| const FLAGS_OFFSET = 8 + 128; | ||
| const SIGPWR = 30; | ||
| const SA_ONSTACK = 0x08000000; | ||
|
|
||
| const buf = new ArrayBuffer(SIGACTION_SIZE); | ||
| const view = new DataView(buf); | ||
|
|
||
| libc.symbols.sigaction(SIGPWR, null, ptr(buf)); | ||
| view.setInt32(FLAGS_OFFSET, view.getInt32(FLAGS_OFFSET, true) | SA_ONSTACK, true); | ||
| libc.symbols.sigaction(SIGPWR, ptr(buf), null); | ||
|
|
||
| // 2. Trigger a fresh dlopen — the fix clears SA_ONSTACK here. | ||
| dlopen("libc.so.6", { getpid: { args: [], returns: FFIType.i32 } }); | ||
|
claude[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| // 3. Exercise the WASM path that calls resetInstructionCacheOnAllThreads. | ||
| // The bytes below are a minimal WASM module with one exported function | ||
| // that loops 10_000 times and returns — enough to trigger compilation. | ||
| const bytes = new Uint8Array([ | ||
| 0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 127, 3, 2, 1, 0, 7, 5, | ||
| 1, 1, 102, 0, 0, 10, 34, 1, 32, 1, 1, 127, 65, 0, 33, 0, 2, 64, 3, 64, | ||
| 32, 0, 65, 1, 106, 33, 0, 32, 0, 65, 144, 206, 0, 72, 13, 0, 11, 11, 32, | ||
| 0, 11, | ||
| ]); | ||
| const inst = new WebAssembly.Instance(new WebAssembly.Module(bytes)); | ||
| (inst.exports.f as () => number)(); | ||
|
|
||
| // 4. A setTimeout that must fire — the bug makes this hang forever. | ||
| await new Promise(r => setTimeout(r, 10)); | ||
| console.log("EVENT_LOOP_ALIVE"); | ||
| `; | ||
|
|
||
| await using proc = Bun.spawn({ | ||
| cmd: [bunExe(), "-e", script], | ||
| env: bunEnv, | ||
| stdout: "pipe", | ||
| stderr: "pipe", | ||
| }); | ||
|
|
||
| // Kill the child after 10 s so a regression shows up as "hung, no output" | ||
| // rather than a stuck test harness. | ||
| const watchdog = setTimeout(() => proc.kill("SIGKILL"), 10_000); | ||
|
|
||
| const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); | ||
| clearTimeout(watchdog); | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| expect(stderr).toBe(""); | ||
| expect(stdout).toContain("EVENT_LOOP_ALIVE"); | ||
| expect(exitCode).toBe(0); | ||
| }); | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.