Skip to content

Fixes #5016 - Fix deadlock in EventIPCTransport.DispatchWailsEvent holding RLock during InvokeSync#5107

Merged
leaanthony merged 4 commits intowailsapp:v3-alphafrom
wayneforrest:fix-dead-lock-ipc-dispatch
Apr 16, 2026
Merged

Fixes #5016 - Fix deadlock in EventIPCTransport.DispatchWailsEvent holding RLock during InvokeSync#5107
leaanthony merged 4 commits intowailsapp:v3-alphafrom
wayneforrest:fix-dead-lock-ipc-dispatch

Conversation

@wayneforrest
Copy link
Copy Markdown
Contributor

@wayneforrest wayneforrest commented Apr 2, 2026

Description

Potential deadlock in EventIPCTransport.DispatchWailsEvent lock ordering issue.
See details in #5106

Fixes #5016

Type of change

Please select the option that is relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration using wails doctor.

  • Windows
  • macOS
  • Linux

If you checked Linux, please specify the distro and version.

Test Configuration

Please paste the output of wails doctor. If you are unable to run this command, please describe your environment in as much detail as possible.

Checklist:

  • I have updated website/src/pages/changelog.mdx with details of this PR
  • My code follows the general coding style of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Summary by CodeRabbit

  • Bug Fixes

    • Resolved a deadlock during event dispatch that could block the app, improving stability.
    • Stopped attempts to execute code on uninitialized or destroyed windows, reducing runtime errors and crashes.
  • Refactor

    • Improved event dispatch responsiveness by snapshotting targets before sending events, while preserving cancellation behavior.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 2, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: add2a2d2-8929-4157-bef0-325e891dd64e

📥 Commits

Reviewing files that changed from the base of the PR and between 506d558 and b383c3b.

📒 Files selected for processing (1)
  • v3/UNRELEASED_CHANGELOG.md
✅ Files skipped from review due to trivial changes (1)
  • v3/UNRELEASED_CHANGELOG.md

Walkthrough

Dispatch now snapshots app.windows under app.windowsLock.RLock() and releases the lock before iterating and calling each window.DispatchWailsEvent(event). Separately, window dispatch now early-returns when the window implementation is nil or the window is destroyed.

Changes

Cohort / File(s) Summary
IPC Event Dispatch
v3/pkg/application/transport_event_ipc.go
Snapshot app.windows while holding windowsLock.RLock(), release the lock, then iterate the snapshot and call DispatchWailsEvent; cancellation checked per-iteration after snapshot.
Window dispatch guard
v3/pkg/application/webview_window.go
DispatchWailsEvent now returns early if w.impl is nil or w.isDestroyed() to avoid ExecJS during teardown/race.
Changelog
v3/UNRELEASED_CHANGELOG.md
Adds a Fixed changelog entry describing the deadlock fix for EventIPCTransport.DispatchWailsEvent (holding RLock during InvokeSync).

Sequence Diagram(s)

sequenceDiagram
  participant App as App
  participant Lock as windowsLock
  participant Snapshot as windows (slice)
  participant Window as Window
  App->>Lock: RLock()
  Lock-->>App: copy app.windows -> Snapshot
  App->>Lock: RUnlock()
  loop for each window in Snapshot
    App->>Window: DispatchWailsEvent(event)
    Window-->>App: InvokeSync / response (may block)
    alt event.IsCancelled()
      App->>App: break loop
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

Suggested labels

Bug, MacOS, v3-alpha, go, size:M, v3

Suggested reviewers

  • leaanthony

Poem

🐰 I nudged the lock and hopped away,
Events now travel out to play.
No freezes, blocks, or tangled thread,
Just gentle hops from bed to bed. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main deadlock fix in EventIPCTransport.DispatchWailsEvent, clearly summarizing the primary change addressing lock ordering issues.
Description check ✅ Passed The description follows the template with the bug fix type selected, references the related issue (#5106), and specifies macOS testing. However, test configuration details and most checklist items remain uncompleted.
Linked Issues check ✅ Passed The PR addresses the deadlock in EventIPCTransport.DispatchWailsEvent (#5106) and restores frameless window minimization on macOS (#5016), meeting the core coding objectives despite incomplete checklist items.
Out of Scope Changes check ✅ Passed The three file changes (transport_event_ipc.go, webview_window.go, changelog) are directly scoped to fixing the deadlock and preventing window dispatch crashes, with no unrelated alterations detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
v3/pkg/application/transport_event_ipc.go (1)

22-27: Please add a regression test for lock inversion deadlock.

This path is concurrency-sensitive; a targeted test that dispatches while windows are added/removed would help prevent regressions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@v3/pkg/application/transport_event_ipc.go` around lines 22 - 27, Add a
concurrent regression test that reproduces the lock-inversion scenario by
repeatedly calling DispatchWailsEvent while other goroutines concurrently
add/remove entries from the windows collection; specifically create a test
(e.g., TestDispatchWhileModifyingWindows) that spins up one goroutine to loop
window.DispatchWailsEvent(event) and another to concurrently add and remove
windows, coordinate start/stop with sync.WaitGroup or channels, enforce a
timeout/context deadline to fail the test on deadlock, and assert progress
(e.g., event delivered or loop iterations completed) to detect hangs; target the
code paths around windows, DispatchWailsEvent and event.IsCancelled to ensure
the concurrency-sensitive path is covered under the race detector.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@v3/pkg/application/transport_event_ipc.go`:
- Around line 22-27: Add a concurrent regression test that reproduces the
lock-inversion scenario by repeatedly calling DispatchWailsEvent while other
goroutines concurrently add/remove entries from the windows collection;
specifically create a test (e.g., TestDispatchWhileModifyingWindows) that spins
up one goroutine to loop window.DispatchWailsEvent(event) and another to
concurrently add and remove windows, coordinate start/stop with sync.WaitGroup
or channels, enforce a timeout/context deadline to fail the test on deadlock,
and assert progress (e.g., event delivered or loop iterations completed) to
detect hangs; target the code paths around windows, DispatchWailsEvent and
event.IsCancelled to ensure the concurrency-sensitive path is covered under the
race detector.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2e8d59ec-2082-44c3-99d0-7767a809b2cd

📥 Commits

Reviewing files that changed from the base of the PR and between bb4fbf9 and 838b00a.

📒 Files selected for processing (1)
  • v3/pkg/application/transport_event_ipc.go

@leaanthony
Copy link
Copy Markdown
Member

leaanthony commented Apr 14, 2026

Thanks for opening this. This introduces a small and unlikely race condition if the window gets deleted after the copy but before the dispatch, the application will crash. that was likely the intent of having a lock there in the first place. There is other code in Window that checks if it is being destroyed. It would be good to follow that pattern here to prevent crashes

@leaanthony
Copy link
Copy Markdown
Member

@wayneforrest wayneforrest force-pushed the fix-dead-lock-ipc-dispatch branch from 87bbd19 to 506d558 Compare April 15, 2026 21:14
@wayneforrest
Copy link
Copy Markdown
Contributor Author

Here is an example: https://github.com/wailsapp/wails/blob/v3-alpha/v3/pkg/application/webview_window_darwin.go#L1639

Morning @leaanthony -- I have added one more commit: 506d558

It guards against dispatching events when the window has been destroyed.

@leaanthony leaanthony enabled auto-merge (squash) April 16, 2026 11:18
@leaanthony leaanthony merged commit 5aa71e1 into wailsapp:v3-alpha Apr 16, 2026
44 of 45 checks passed
@leaanthony
Copy link
Copy Markdown
Member

Thanks for doing this 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants