fix(linux): re-apply signal handlers periodically to survive JSC lazy init#5507
Conversation
… init WebKit's JavaScriptCore (JSC) lazily installs signal handlers (SIGSEGV for JIT crash recovery, SIGUSR1 for GC thread sync) when JavaScript first executes - not at WebView creation. These handlers are registered without SA_ONSTACK, overwriting Go's handler which requires it. The existing one-shot fix runs before any JS executes, so JSC wipes it out immediately when it initialises. A 50ms periodic timer (100 iterations = 5s) running on the GTK main thread re-applies install_signal_handlers() throughout the JSC initialisation window, ensuring Go's SA_ONSTACK requirement is always satisfied. Fixes #5506
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughAdds C and Go changes that repeatedly re-apply install_signal_handlers() (now covering SIGUSR1) via a GLib timeout scheduler and calls to re-run the fix during WebView creation and after page load (DomReady / WEBKIT_LOAD_FINISHED). ChangesSignal Handler Timeout Retry
Sequence Diagram(s)sequenceDiagram
participant App as Go App
participant WebView
participant GLibTimer as GLib Timer
participant C as install_signal_handlers
App->>WebView: create WebView (first)
App->>C: C.install_signal_handlers() (initial)
App->>C: C.schedule_signal_handler_fix() (starts GLib timer)
WebView->>C: WebKit/JSC may install signal handlers (including SIGUSR1)
GLibTimer->>C: timeout tick -> call install_signal_handlers() (every 50ms)
C-->>GLibTimer: continue until countdown expires (~5s)
WebView->>App: WEBKIT_LOAD_FINISHED / DomReady
App->>C: C.install_signal_handlers() (re-apply after load)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR addresses Linux startup crashes caused by WebKit JavaScriptCore lazily overwriting Go’s signal handlers without SA_ONSTACK by periodically re-applying Wails’ install_signal_handlers() during the early initialization window (instead of relying only on a one-shot fix).
Changes:
- Add a GLib
g_timeout_add_fulltimer (50ms, 100 iterations) to repeatedly callinstall_signal_handlers()for ~5 seconds. - Introduce
schedule_signal_handler_fix()for v3 GTK4 (C + header) and invoke it fromappNew(). - Apply the same periodic scheduling approach to v3 GTK3 and v2 Linux frontend initialization.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| v3/pkg/application/linux_cgo.h | Declares schedule_signal_handler_fix() for GTK4 build path. |
| v3/pkg/application/linux_cgo.go | Schedules the periodic signal-handler reapply during app creation (GTK4 path). |
| v3/pkg/application/linux_cgo.c | Implements the periodic timer callback + scheduler (GTK4 path). |
| v3/pkg/application/linux_cgo_gtk3.go | Adds equivalent periodic timer logic and schedules it once (GTK3 path). |
| v2/internal/frontend/desktop/linux/frontend.go | Adds periodic timer scheduling after GTK init (v2 path). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…imer Addresses code review feedback on #5507: - Add SIGUSR1 to install_signal_handlers(): JSC uses SIGUSR1 for GC thread synchronisation and installs it without SA_ONSTACK (visible as "Overriding existing handler for signal 10" in stderr). The fix_signal helper only adds SA_ONSTACK to whatever handler is already registered, so this is safe for both Go's and JSC's handler. - Hook WEBKIT_LOAD_FINISHED (v3 GTK4/GTK3) and DomReady (v2): by page-load completion JSC is guaranteed to have initialised and installed all its signal handlers. A targeted call to install_signal_handlers() here provides a deterministic, event-driven fix that complements the periodic timer. - Anchor the GTK4 periodic timer to first WebView creation (sync.Once inside windowNewWebview) rather than appNew(), mirroring the GTK3 pattern. This ensures the 5s coverage window starts when JSC can actually initialise, not before any WebView exists.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@v3/pkg/application/linux_cgo.go`:
- Around line 1196-1201: The GTK4 path currently only calls
C.schedule_signal_handler_fix() inside fixSignalHandlers.Do, leaving a 0–50ms
window; update the fixSignalHandlers.Do block to first call
C.install_signal_handlers() immediately (mirroring the GTK3 path) and then call
C.schedule_signal_handler_fix() so the handlers are installed once right away
before the periodic 50ms timer is armed; reference the existing
fixSignalHandlers.Do, C.install_signal_handlers, and
C.schedule_signal_handler_fix symbols when making the change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 6986ea11-ee10-4b99-8ca0-14c6e81e8d7f
📒 Files selected for processing (4)
v2/internal/frontend/desktop/linux/frontend.gov3/pkg/application/linux_cgo.cv3/pkg/application/linux_cgo.gov3/pkg/application/linux_cgo_gtk3.go
|
Verified this fixes a real-world Wails 2 app on Ubuntu 26.04 LTS + libwebkit2gtk-4.1-0 2.52.3-0ubuntu0.26.04.2. Test app: nebari-dev/nebi at Test method:
With this PR applied: app runs cleanly, serves real HTTP traffic through the embedded asset server, exits cleanly on window close. Reproduced over multiple runs. Looking forward to the merge — would let us delete the workaround. (Downstream tracking issue: nebari-dev/nebi#350.) |
…dler clobbering (#351) * fix(desktop): re-apply SA_ONSTACK so WebKitGTK JSC doesn't crash Go runtime Wails 2.11.0 installed SA_ONSTACK on signal handlers before gtk_init, which let WebKit's later signal install (without SA_ONSTACK) clobber it. Bump to Wails 2.12.0, which defers the fix to g_idle_add after gtk_init, AND add a linux-only background ticker that re-applies SA_ONSTACK on SIGSEGV/SIGBUS/etc. JavaScriptCore installs its GC/Wasm trap handlers lazily on first JS context creation — which can land after the one-shot idle pass — so a periodic re-fix is needed to be reliable on Ubuntu 24.04+ / libwebkit2gtk-4.1. Verified: nebi-desktop now boots, serves the embedded API for 30+ seconds of clicking around, and exits cleanly on window close. * fix(desktop): document upstream removal condition and add SIGUSR1 Reference upstream Wails fix wailsapp/wails#5507 (closes wails#5506) so a future maintainer knows this Go-side ticker can be deleted once the Wails release containing that PR lands and we've bumped to it. Also add SIGUSR1 (JSC GC thread sync) to the fix list, matching the additional signal that the upstream PR fixes.
…ze (#5530) WebKit's JavaScriptCore uses SIGUSR1 to suspend/resume threads for conservative GC stack scanning. The signal-handler fix added in alpha.97 (#5507) re-applied SA_ONSTACK to every signal it touched, including SIGUSR1. Once JSC installs its own SIGUSR1 handler it owns the signal (Go no longer handles it), so forcing SA_ONSTACK makes that handler run on Go's alternate signal stack, breaking GC thread synchronisation. This froze the WebKit UI during idle garbage collection (most visibly with the inspector open) while the Go backend kept running. Remove fix_signal(SIGUSR1) from install_signal_handlers in v3 (GTK4 + GTK3) and v2. The genuine #5506 fix for SIGSEGV/SIGBUS (which Go needs SA_ONSTACK for) is unaffected. Fixes #5527 https://claude.ai/code/session_01AtT1CjDNRArXv1eddXte2a Co-authored-by: Claude <noreply@anthropic.com>
Problem
Closes #5506
WebKit's JavaScriptCore (JSC) lazily installs signal handlers when JavaScript first executes — not at WebView creation time. These handlers (SIGSEGV for JIT crash recovery, SIGUSR1 for GC thread synchronisation) are registered without
SA_ONSTACK, overwriting Go's handlers which require the flag.When a JIT page fault occurs, the kernel delivers SIGSEGV on the normal stack instead of the alternate signal stack. JSC's handler runs and calls Go's handler as a fallback; Go's
sigtrampdetects the missingSA_ONSTACKflag and panics:Root Cause
The existing one-shot fix (
g_idle_addin v2, direct call in v3) runs before any JavaScript has executed. JSC installs its bad handlers later — when the first JS runs — wiping out the fix entirely.The reporter's workaround confirmed this: a
g_timeout_addpolling at 50ms intervals prevented the crash because it continuously re-applied the fix through the JSC initialisation window.Fix
Add a
g_timeout_add_fullperiodic timer (50ms, 100 iterations = 5 seconds) on the GTK main thread that re-appliesinstall_signal_handlers()throughout the JSC lazy-initialisation window. Theg_freedestroy-notify prevents a memory leak if the app exits before the timer completes.The existing one-shot idle/direct calls are preserved as the "first immediate fix" layer. The periodic timer takes over from there and covers the race window.
Files Changed
v2/internal/frontend/desktop/linux/frontend.go— periodic timer added tofix_signal_handlers_after_gtk_init()v3/pkg/application/linux_cgo.c+.h+.go— newschedule_signal_handler_fix()called fromappNew()v3/pkg/application/linux_cgo_gtk3.go— same logic inline, called insidefixSignalHandlers.DoSummary by CodeRabbit