Skip to content

feat(v2): add runtime.ResetSignalHandlers() for Linux panic recovery#4921

Merged
leaanthony merged 2 commits into
masterfrom
fix/linux-panic-recovery-runtime-api
Feb 2, 2026
Merged

feat(v2): add runtime.ResetSignalHandlers() for Linux panic recovery#4921
leaanthony merged 2 commits into
masterfrom
fix/linux-panic-recovery-runtime-api

Conversation

@leaanthony

@leaanthony leaanthony commented Jan 28, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds runtime.ResetSignalHandlers() function to allow panic recovery from nil pointer dereferences on Linux
  • Adds documentation for the new function in the runtime reference
  • Adds troubleshooting guide for Linux signal handling issues
  • Adds example project to reproduce and verify the fix

Problem

On Linux, WebKit (used for the webview) installs signal handlers without the SA_ONSTACK flag. This prevents Go from properly recovering from panics caused by SIGSEGV (nil pointer dereference) and other memory access violations. Users experience crashes with:

signal 11 received but handler not on signal stack
fatal error: non-Go code set up signal handler without SA_ONSTACK flag

Even with defer/recover(), the panic cannot be caught.

Solution

Add a new runtime function that resets signal handlers with the proper SA_ONSTACK flag:

go func() {
    defer func() {
        if err := recover(); err != nil {
            log.Printf("Recovered: %v", err)
        }
    }()
    runtime.ResetSignalHandlers()  // Call before risky code
    // Code that might panic...
}()

The function must be called immediately before potentially panicking code because WebKit may reset the handlers at any time.

Changes

  • v2/pkg/runtime/signal_linux.go - Linux implementation using cgo
  • v2/pkg/runtime/signal_other.go - No-op stub for macOS/Windows
  • v2/examples/panic-recovery-test/ - Example project to reproduce/verify
  • website/docs/reference/runtime/intro.mdx - API documentation
  • website/docs/guides/linux.mdx - Troubleshooting guide

Test plan

How to reproduce and verify

  1. Build the example:

    cd v2/examples/panic-recovery-test
    wails build -tags webkit2_41
  2. Run the application:

    ./build/bin/panic-recovery-test
  3. Wait ~10 seconds (the app auto-calls Greet after 5s, then waits another 5s before the nil pointer dereference)

Expected result (with fix)

The panic is recovered and you see:

------------------------------"invalid memory address or nil pointer dereference"

The application continues running.

To verify the fix is needed

Comment out the runtime.ResetSignalHandlers() call in app.go and rebuild. The application will crash with a fatal signal 11 error.

Fixes #3965

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a runtime API to configure signal handlers, improving panic recovery on Linux.
    • Added a small example app demonstrating panic recovery and how to use the API.
  • Documentation

    • Added a Linux guide covering signal handling and panic recovery with examples.
    • Added reference docs for the new runtime API.
  • Examples

    • Added a full panic-recovery example (frontend, backend, and README).

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 28, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a Linux-specific runtime helper, ResetSignalHandlers(), which calls a cgo-backed C routine to set SA_ONSTACK on critical signals; provides a no-op implementation for non-Linux platforms and documents usage with a new panic-recovery example and docs.

Changes

Cohort / File(s) Summary
Runtime — Linux implementation
v2/pkg/runtime/signal_linux.go
New linux-only ResetSignalHandlers() that uses cgo to call C functions which set SA_ONSTACK for SIGSEGV, SIGBUS, SIGFPE, SIGABRT.
Runtime — Non-Linux fallback
v2/pkg/runtime/signal_other.go
New non-Linux build-tagged file exposing the same ResetSignalHandlers() API as a no-op.
Documentation
website/docs/guides/linux.mdx, website/docs/reference/runtime/intro.mdx
Adds docs describing the Linux signal/SA_ONSTACK issue, usage guidance and examples for ResetSignalHandlers().
Example app (Go)
v2/examples/panic-recovery-test/app.go, v2/examples/panic-recovery-test/main.go, v2/examples/panic-recovery-test/go.mod, v2/examples/panic-recovery-test/wails.json, v2/examples/panic-recovery-test/README.md
New Wails example demonstrating calling ResetSignalHandlers() before inducing a panic and showing recovery flow; includes app wiring and module metadata.
Example frontend (static + build)
v2/examples/panic-recovery-test/frontend/index.html, .../frontend/package.json, .../frontend/src/*, .../frontend/src/assets/*, .../frontend/src/main.js, .../frontend/src/style.css, .../frontend/src/app.css
Adds frontend assets, styles, and a simple UI that calls the Go Greet API; includes font and license asset.
WailsJS runtime & bindings
v2/examples/panic-recovery-test/frontend/wailsjs/go/main/App.d.ts, .../App.js, .../runtime/runtime.d.ts, .../runtime/runtime.js, .../runtime/package.json
Adds generated JS/TS bindings and runtime wrappers exposing window/runtime APIs used by the example frontend.

Sequence Diagram(s)

sequenceDiagram
  participant App as Go app (caller)
  participant Runtime as runtime.ResetSignalHandlers()
  participant C as cgo C helper
  participant OS as Kernel / libc / WebKit handlers

  App->>Runtime: call ResetSignalHandlers()
  Runtime->>C: call fix_all_signals()
  C->>OS: set sigaction with SA_ONSTACK for SIGSEGV,SIGBUS,SIGFPE,SIGABRT
  OS-->>C: ack
  C-->>Runtime: return
  Runtime-->>App: return
  Note right of OS: Signals now delivered with SA_ONSTACK
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

go, Enhancement, size:L, lgtm

Suggested reviewers

  • atterpac

Poem

🐰 I twitched my nose by Linux streams, and nudged the signal stacks,
I set the flags so panics bounce and land on safer tracks.
A tiny hop, a clever tweak — the goroutine stands tall,
With SA_ONSTACK in its paws, it tumbles, then stands all! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.07% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding runtime.ResetSignalHandlers() for Linux panic recovery, matching the core objective.
Linked Issues check ✅ Passed The PR fully implements the requirements from #3965: adds ResetSignalHandlers() to enable panic recovery on Linux from nil pointer dereference signals, provides documentation, and includes a working example demonstrating the fix.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the PR objectives: runtime implementation, documentation, and a panic-recovery example demonstrating the fix. No unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread .github/workflows/automated-releases.yml Fixed
Comment thread .github/workflows/automated-releases.yml Fixed
Comment thread .github/workflows/automated-releases.yml Fixed
Comment thread .github/workflows/automated-releases.yml Fixed
Comment thread .github/workflows/automated-releases.yml Fixed
Comment thread .github/workflows/build-cross-image.yml Fixed
Comment thread .github/workflows/build-cross-image.yml Fixed
Comment thread .github/workflows/build-cross-image.yml Fixed
Comment thread .github/workflows/publish-npm.yml Fixed
Comment thread .github/workflows/test-simple.yml Fixed
Add a new runtime function that allows users to reset signal handlers
before code that might panic from nil pointer dereferences.

On Linux, WebKit installs signal handlers without the SA_ONSTACK flag,
which prevents Go from properly recovering from panics caused by
SIGSEGV and other signals. This function adds SA_ONSTACK to the
relevant signal handlers (SIGSEGV, SIGBUS, SIGFPE, SIGABRT).

Usage:
```go
go func() {
    defer func() {
        if err := recover(); err != nil {
            log.Printf("Recovered: %v", err)
        }
    }()
    runtime.ResetSignalHandlers()
    // Code that might panic...
}()
```

The function is a no-op on macOS and Windows.

Fixes #3965

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@leaanthony leaanthony force-pushed the fix/linux-panic-recovery-runtime-api branch from efef6b1 to 6395679 Compare January 28, 2026 19:50
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jan 28, 2026

Copy link
Copy Markdown

Deploying wails with  Cloudflare Pages  Cloudflare Pages

Latest commit: 982ddd2
Status: ✅  Deploy successful!
Preview URL: https://16c34357.wails.pages.dev
Branch Preview URL: https://fix-linux-panic-recovery-run.wails.pages.dev

View logs

@github-actions github-actions Bot added Documentation Improvements or additions to documentation Linux runtime v2-only labels Jan 28, 2026
Add an example that demonstrates the Linux signal handler issue (#3965)
and verifies the fix using runtime.ResetSignalHandlers().

The example includes:
- A Greet function that triggers a nil pointer dereference after a delay
- Auto-call from frontend after 5 seconds
- README with reproduction steps

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
47.2% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@v2/examples/panic-recovery-test/frontend/src/main.js`:
- Around line 7-15: The HTML template has an extra closing </div> with no
matching opener; fix by adding a corresponding opening wrapper div (e.g., <div
class="container">) before the <div class="result" id="result"> so the DOM nests
correctly around the `#logo`, `#result` and `#input` elements, then verify the greet()
button and element IDs (name, result, input, logo) still match expected
selectors and event handlers.
🧹 Nitpick comments (7)
v2/examples/panic-recovery-test/README.md (3)

9-12: Add language identifier to fenced code block.

The error output code block should specify a language for proper syntax highlighting.

📝 Suggested fix
-```
+```text
 signal 11 received but handler not on signal stack
 fatal error: non-Go code set up signal handler without SA_ONSTACK flag
-```
+```

58-60: Add language identifier to fenced code block.

The expected output code block should specify a language for consistency.

📝 Suggested fix
-```
+```text
 ------------------------------"invalid memory address or nil pointer dereference"
-```
+```

73-76: Convert bare URLs to proper markdown links.

Using markdown link syntax improves readability and follows markdown best practices.

📝 Suggested fix
 ## Related
 
-- Issue: https://github.com/wailsapp/wails/issues/3965
-- Original fix PR: https://github.com/wailsapp/wails/pull/2152
+- Issue: [`#3965`](https://github.com/wailsapp/wails/issues/3965)
+- Original fix PR: [`#2152`](https://github.com/wailsapp/wails/pull/2152)
v2/examples/panic-recovery-test/frontend/src/main.js (1)

31-42: Redundant try-catch block.

The outer try-catch only catches synchronous errors, but Greet() returns a Promise. The .catch() handler already handles Promise rejections, making the outer try-catch unnecessary.

♻️ Suggested simplification
     // Call App.Greet(name)
-    try {
-        Greet(name)
-            .then((result) => {
-                // Update result with data back from App.Greet()
-                resultElement.innerText = result;
-            })
-            .catch((err) => {
-                console.error(err);
-            });
-    } catch (err) {
-        console.error(err);
-    }
+    Greet(name)
+        .then((result) => {
+            // Update result with data back from App.Greet()
+            resultElement.innerText = result;
+        })
+        .catch((err) => {
+            console.error(err);
+        });
v2/examples/panic-recovery-test/frontend/wailsjs/runtime/runtime.d.ts (2)

21-26: Minor formatting inconsistency in interface declaration.

The Screen interface has inconsistent spacing around colons compared to other interfaces (width : number vs width: number).

📝 Suggested fix
 export interface Screen {
     isCurrent: boolean;
     isPrimary: boolean;
-    width : number
-    height : number
+    width: number;
+    height: number;
 }

239-249: Minor formatting inconsistencies in function declarations.

A few function declarations have minor formatting issues: missing space after comma, and missing semicolons.

📝 Suggested fixes
 // [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop)
 // OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
-export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void
+export function OnFileDrop(callback: (x: number, y: number, paths: string[]) => void, useDropTarget: boolean): void;
 
 // [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff)
 // OnFileDropOff removes the drag and drop listeners and handlers.
-export function OnFileDropOff() :void
+export function OnFileDropOff(): void;
 
 // Check if the file path resolver is available
 export function CanResolveFilePaths(): boolean;
 
 // Resolves file paths for an array of files
-export function ResolveFilePaths(files: File[]): void
+export function ResolveFilePaths(files: File[]): void;
v2/examples/panic-recovery-test/frontend/wailsjs/runtime/runtime.js (1)

59-62: Consider using modern spread syntax for clarity.

The expression [eventName].slice.call(arguments) works but is non-idiomatic. Using rest parameters or spread syntax would be clearer and more maintainable.

♻️ Suggested improvement
-export function EventsEmit(eventName) {
-    let args = [eventName].slice.call(arguments);
-    return window.runtime.EventsEmit.apply(null, args);
+export function EventsEmit(eventName, ...args) {
+    return window.runtime.EventsEmit(eventName, ...args);
 }

Comment on lines +7 to +15
document.querySelector('#app').innerHTML = `
<img id="logo" class="logo">
<div class="result" id="result">Please enter your name below 👇</div>
<div class="input-box" id="input">
<input class="input" id="name" type="text" autocomplete="off" />
<button class="btn" onclick="greet()">Greet</button>
</div>
</div>
`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix unmatched HTML closing tag.

The template has an unmatched closing </div> tag on line 14. The structure shows opening tags for result and input-box divs, but there's an extra closing tag without a corresponding opening container.

🐛 Suggested fix - add opening container div
 document.querySelector('#app').innerHTML = `
-    <img id="logo" class="logo">
+    <div>
+      <img id="logo" class="logo">
       <div class="result" id="result">Please enter your name below 👇</div>
       <div class="input-box" id="input">
         <input class="input" id="name" type="text" autocomplete="off" />
         <button class="btn" onclick="greet()">Greet</button>
       </div>
     </div>
 `;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
document.querySelector('#app').innerHTML = `
<img id="logo" class="logo">
<div class="result" id="result">Please enter your name below 👇</div>
<div class="input-box" id="input">
<input class="input" id="name" type="text" autocomplete="off" />
<button class="btn" onclick="greet()">Greet</button>
</div>
</div>
`;
document.querySelector('#app').innerHTML = `
<div>
<img id="logo" class="logo">
<div class="result" id="result">Please enter your name below 👇</div>
<div class="input-box" id="input">
<input class="input" id="name" type="text" autocomplete="off" />
<button class="btn" onclick="greet()">Greet</button>
</div>
</div>
`;
🤖 Prompt for AI Agents
In `@v2/examples/panic-recovery-test/frontend/src/main.js` around lines 7 - 15,
The HTML template has an extra closing </div> with no matching opener; fix by
adding a corresponding opening wrapper div (e.g., <div class="container">)
before the <div class="result" id="result"> so the DOM nests correctly around
the `#logo`, `#result` and `#input` elements, then verify the greet() button and
element IDs (name, result, input, logo) still match expected selectors and event
handlers.

"node": "^10 || ^12 || >=14"
}
},
"node_modules/rollup": {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High severity vulnerability may affect your project—review required:
Line 569 lists a dependency (rollup) with a known High severity vulnerability.

ℹ️ Why this matters

Affected versions of rollup are vulnerable to Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting').

References: GHSA, CVE

To resolve this comment:
Check if you use Rollup to bundle JavaScript with import.meta.url and the output format is set to cjs, umd, or iife formats, while allowing users to inject scriptless HTML elements with unsanitized name attributes.

💬 Ignore this finding

To ignore this, reply with:

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

You can view more details on this finding in the Semgrep AppSec Platform here.

@leaanthony leaanthony merged commit 01b661f into master Feb 2, 2026
35 of 36 checks passed
@leaanthony leaanthony deleted the fix/linux-panic-recovery-runtime-api branch February 2, 2026 07:56
@leaanthony leaanthony mentioned this pull request Feb 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Documentation Improvements or additions to documentation Linux runtime v2-only

Projects

None yet

Development

Successfully merging this pull request may close these issues.

app crash if "invalid memory address or nil pointer dereference"

2 participants