Skip to content

Close Web Inspector before browser host teardown - #3835

Merged
austinywang merged 3 commits into
mainfrom
issue-3828-web-inspector-crash
May 11, 2026
Merged

austinywang merged 3 commits into
mainfrom
issue-3828-web-inspector-crash

Conversation

@austinywang

@austinywang austinywang commented May 11, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #3828

Crash signature

cmux 0.64.3 can crash on the main thread when closing a window or pane containing a browser WKWebView whose Web Inspector is open:

EXC_BAD_ACCESS (KERN_INVALID_ADDRESS at 0x170)
0  WebKit -[WKWebInspectorUIProxyObjCAdapter inspectorViewControllerDidBecomeActive:] + 88
1  WebKit -[WKInspectorViewController inspectorWKWebViewDidBecomeActive:] + 60
2  WebKit -[WKInspectorWKWebView _handleWindowDidBecomeKey:] + 92
...
22 WebKit -[WKWebInspectorUIProxyObjCAdapter windowWillClose:] + 52
30 AppKit -[NSWindow __close] + 376
31 AppKit -[NSApplication(NSResponder) sendAction:to:from:]
...
44 cmux   NSWindow.cmux_sendEvent(_:) + 788

Repro notes

Attempted the requested baseline command before code changes: ./scripts/reload.sh --tag issue-3828-web-inspector-crash-baseline --launch. The first attempt was interrupted by the shared build queue before launch; a retry was still waiting on the global reload lock, so I stopped only that queued retry before editing to avoid it launching a non-baseline build after changes. A fresh local crash report at ~/Library/Logs/DiagnosticReports/cmux-2026-05-10-164628.ips matched the exact signature above, including the 0x170 read, WKInspectorWKWebView _handleWindowDidBecomeKey, and NSWindow.cmux_sendEvent frame.

Manual repro sequence used for the live smoke path:

  1. Open browser pane.
  2. Open Web Inspector via the production DevTools toolbar button.
  3. Exercise inspector/window close behavior and check DiagnosticReports for a new crash.

Design memo

The fix closes Web Inspector synchronously before AppKit starts tearing down the parent host. WebViewInspectorTeardown.closeAllInspectors(in:) walks the closing window's view tree for production WKWebView instances and closes any visible or attached inspector through the same WebKit _inspector object cmux already uses for DevTools. The helper is called from windowShouldClose for main windows, pane teardown, popup teardown, and app termination. It does not schedule DispatchQueue, Task, or delayed retries, because the failing observer must be removed on the same runloop turn before windowWillClose: and key-window notifications cascade through WebKit.

NSWindow.cmux_sendEvent audit: the swizzle only performs event routing, focus guard context, key timing, and folder-drag/window-move suppression before forwarding to AppKit. It does not perform synchronous teardown or pre-empt normal close ordering, so the fix belongs in the close lifecycle rather than the event swizzle.

Regression tests

Two-commit structure:

  1. 8d43a77f3 adds failing regression coverage only.
  2. 228390fa7 adds the synchronous inspector teardown fix.

Added @MainActor tests in BrowserDeveloperToolsVisibilityPersistenceTests that use the production BrowserPanel/CmuxWebView path and the same inspector SPI hook used by existing DevTools tests:

  • testPaneCloseClosesVisibleInspectorSynchronouslyBeforeWebViewTeardown
  • testWindowCloseClosesContainedBrowserInspectorBeforeWindowWillClose

Local unit tests were not run because this issue forbids direct xcodebuild; CI is the validation path.

Manual verification

Case Result Notes
Browser pane + Web Inspector, close cmux window Not run manually Covered by new regression test + CircleCI macOS unit tests; UI automation could not reliably target the parent window behind the detached inspector without disrupting the final launch requirement
Browser pane + Web Inspector, close pane Not run manually Covered by new regression test + CircleCI macOS unit tests
Web Inspector open, Cmd+Q app Not run manually Code path covered by applicationShouldTerminate/applicationWillTerminate hook; not exercised manually to preserve final launched dev app
Close inspector window itself Pass Opened real Web Inspector from the production DevTools toolbar button, clicked inspector close button, parent browser window remained open
Reload WKWebView URL, then close window Not run manually Not completed in UI smoke pass
Repeat timing-sensitive cases 3-5x Not run manually Not completed in UI smoke pass
Check ~/Library/Logs/DiagnosticReports/cmux-*.ips Pass No crash report newer than the pre-fix cmux-2026-05-10-164628.ips after launch/smoke interaction

Validation

  • git diff --check passed.
  • GitHub Actions checks passed: workflow-guard-tests, remote-daemon-tests, web-typecheck, web-db-migrations, activation-session.
  • CircleCI passed: macos-debug-build, macos-release-build, macos-unit-tests.
  • Vercel production/staging preview deploy contexts passed.
  • Branch pushed to origin (manaflow-ai/cmux) only.
  • ./scripts/reload.sh --tag issue-3828-web-inspector-crash --launch succeeded after freeing this issue's stale baseline DerivedData and launched cmux DEV issue-3828-web-inspector-crash.

Note

Medium Risk
Touches window-close and app-termination paths and relies on WebKit private inspector SPI; incorrect ordering could regress close behavior or DevTools state, but changes are localized and covered by new tests.

Overview
Closes any open WebKit Web Inspector synchronously before AppKit begins tearing down windows, panes, or popups to prevent a crash during close.

Introduces WebViewInspectorTeardown to walk a window’s view tree, find non-inspector WKWebViews, and invoke the inspector close SPI when visible/attached. This teardown is now triggered from main window windowShouldClose, BrowserPanel.close(), popup close/delegate hooks, and app quit/terminate (applicationShouldTerminate/applicationWillTerminate).

Adds unit tests asserting inspectors are closed before WKWebView teardown and before NSWindow.willClose fires during window close.

Reviewed by Cursor Bugbot for commit e1c31b8. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • Bug Fixes

    • Developer tools are now properly closed and cleaned up when windows close or during application shutdown
    • Enhanced shutdown sequence to ensure inspector state is fully released before app termination
  • Tests

    • Added lifecycle tests verifying proper developer tools cleanup during window closure and panel shutdown scenarios

Review Change Stack

The WebKit crash occurs when cmux enters browser pane or window teardown while the inspector remains visible, so the regression locks the expected ordering at both close surfaces before changing production code.

Constraint: Regression must use the production BrowserPanel and CmuxWebView path rather than a stripped-down WKWebView

Confidence: high

Scope-risk: narrow

Tested: Not run locally; direct xcodebuild is forbidden for this issue

Not-tested: CI failure evidence for the test-only commit is pending
WebKit can leave an inspector frontend observing key-window notifications after its parent inspector proxy starts closing. The fix establishes one synchronous teardown helper and invokes it from the pane, popup, main-window, and app-quit close paths before delegates and windows enter their normal teardown cascade.

Constraint: Direct xcodebuild is forbidden for this issue; verification must use sanctioned reload and CI paths

Rejected: Add delayed or defensive cleanup after windowWillClose | the crash happens inside the same AppKit close cascade

Rejected: Only patch BrowserPanel.close | main-window close can deliver windowWillClose before pane teardown runs

Confidence: high

Scope-risk: moderate

Directive: Keep WebViewInspectorTeardown synchronous; do not replace it with DispatchQueue, Task, or delayed retry cleanup

Tested: git diff --check

Not-tested: Local unit tests and app build pending sanctioned reload/CI workflow
@vercel

vercel Bot commented May 11, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 11, 2026 5:55am
cmux-staging Building Building Preview, Comment May 11, 2026 5:55am

@coderabbitai

coderabbitai Bot commented May 11, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The PR adds synchronous Web Inspector teardown across panel, popup, main window close, and app termination paths. It introduces WebViewInspectorTeardown utilities and calls them from BrowserPanel, BrowserPopupWindowController, and AppDelegate; tests validate inspector close ordering.

Changes

Web Inspector Teardown on Window/Pane Close

Layer / File(s) Summary
WebViewInspectorTeardown Utility
Sources/Panels/BrowserPanel.swift
New WebViewInspectorTeardown type with static methods to close inspectors for a WKWebView, an NSWindow, or [NSWindow]. Scans view hierarchies, filters inspector-front WebViews, checks isVisible/isAttached, and invokes the inspector's close selector when appropriate.
BrowserPanel Teardown Integration
Sources/Panels/BrowserPanel.swift
Added closeDeveloperToolsForTeardown() -> Bool that cancels pending devtools transition work, clears visibility/restore state, calls WebViewInspectorTeardown.closeInspector(for:), forces preferred devtools visibility to false, and returns whether an inspector was closed. BrowserPanel.close() now calls this helper before unfocus/WebView delegate cleanup.
BrowserPopupWindowController Teardown
Sources/Panels/BrowserPopupWindowController.swift
closePopup() now calls WebViewInspectorTeardown.closeAllInspectors(in: panel) before closing. Implements windowShouldClose(_:) to close all inspectors for the window and allow close. windowWillClose(_:) calls WebViewInspectorTeardown.closeInspector(for: webView) early in the close sequence.
AppDelegate Termination Teardown
Sources/AppDelegate.swift
MainWindowController.windowShouldClose closes inspectors for the window. applicationShouldTerminate calls closeAllWebInspectorsBeforeAppTeardown() immediately before early .terminateNow returns in DEV/confirmed/disabled-warning paths. closeAllWebInspectorsBeforeAppTeardown() calls WebViewInspectorTeardown.closeAllInspectors(in: NSApp.windows). applicationWillTerminate calls the helper after setting isTerminatingApp = true.
Lifecycle Tests & Helpers
cmuxTests/BrowserConfigTests.swift
Adds spinRunLoopOneTick() and window(withId:) test helpers. Adds tests verifying that BrowserPanel.close() synchronously closes visible inspectors before WebView teardown and that window.performClose(nil) results in inspectors being closed by the time NSWindow.willCloseNotification is observed.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant BrowserPanel
  participant BrowserPopupWindowController
  participant AppDelegate
  participant WebViewInspectorTeardown
  User->>BrowserPanel: trigger pane close / popup close
  BrowserPanel->>WebViewInspectorTeardown: closeInspector(for: webView)
  BrowserPopupWindowController->>WebViewInspectorTeardown: closeAllInspectors(in: panel)
  User->>AppDelegate: quit
  AppDelegate->>WebViewInspectorTeardown: closeAllInspectors(in: NSApp.windows) (via helper)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • manaflow-ai/cmux#1150: Modified popup lifecycle and popup close handling; overlaps with popup windowShouldClose/windowWillClose changes.
  • manaflow-ai/cmux#1230: Changes to BrowserPanel developer-tools lifecycle; related to devtools visibility and teardown logic.
  • manaflow-ai/cmux#1220: Prior edits to BrowserPanel devtools hide/close logic that intersect with this PR's teardown changes.

"🐰 I hop through windows, careful and spry,
I close every inspector before they say goodbye.
No stray pointers, no crash in the night,
A tidy shutdown — everything's right. 🥕"

🚥 Pre-merge checks | ✅ 14 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.34% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (14 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: closing Web Inspector before browser host teardown, which directly addresses the crash issue being fixed.
Linked Issues check ✅ Passed All code objectives from issue #3828 are met: synchronous inspector closing via new WebViewInspectorTeardown helper is implemented across all relevant close surfaces (pane, window, popup, app termination), regression tests verify synchronous closure before teardown, and the fix prevents the use-after-free crash.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the Web Inspector crash: new WebViewInspectorTeardown enum and inspector-closing logic in BrowserPanel, BrowserPopupWindowController, AppDelegate, and targeted regression tests. No unrelated modifications detected.
Cmux Swift Actor Isolation ✅ Passed All Swift changes maintain proper @MainActor isolation. WebViewInspectorTeardown enum is @MainActor. New functions are in @MainActor classes. No unsafe patterns introduced.
Cmux Swift Blocking Runtime ✅ Passed Production code introduces no blocking primitives. WebViewInspectorTeardown uses synchronous calls with main-thread assertions. Test code uses allowed deterministic RunLoop scaffolding.
Cmux No Hacky Sleeps ✅ Passed PR contains only Swift code. Custom check targets non-Swift production code (TS/JS/shell/build scripts). Swift primitives covered by separate rule. Check not applicable.
Cmux Swift Concurrency ✅ Passed PR adds modern @MainActor-isolated synchronous code. No background DispatchQueue, Task, Combine, or completion handlers in new code. XCTest synchronization is appropriate.
Cmux Swift @Concurrent ✅ Passed All new methods are synchronous, properly isolated to @MainActor, and have no async/await or @concurrent issues. Teardown work is intentionally UI-bound on the main thread.
Cmux Swift File And Package Boundaries ✅ Passed 116 lines added across oversized files (under 250 threshold). WebViewInspectorTeardown is ~100 focused lines for inspector teardown. Single responsibility, no mixed concerns, appropriate AppKit glue.
Cmux Swift Logging ✅ Passed New production code has no logging violations. WebViewInspectorTeardown enum and related methods contain no print, NSLog, debugPrint, or dump statements.
Cmux Swiftui State Layout ✅ Passed PR adds AppKit code and tests. BrowserPanel is an AppKit bridge class using @Published with @ObservedObject in SwiftUI—explicitly allowed. No SwiftUI state violations.
Cmux Architecture Rethink ✅ Passed Synchronous utility fix for closing inspectors before AppKit teardown cascade. @MainActor, no delays/observers/new state. Single path. Required platform bridge documented.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR adds no new windows. Changes only add teardown logic to existing close paths and test fixtures. No NSWindow/NSPanel declarations added.
Description check ✅ Passed The PR description comprehensively covers the crash signature, repro steps, design rationale, regression tests, manual verification, and validation results.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-3828-web-inspector-crash

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

@greptile-apps

greptile-apps Bot commented May 11, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a EXC_BAD_ACCESS crash (0x170 read in WKWebInspectorUIProxyObjCAdapter) that occurred when AppKit tore down a window or pane while a WKWebView Web Inspector was still attached. The fix closes the inspector synchronously through the same _inspector SPI object cmux already uses, ensuring WebKit unregisters its window observer before the close cascade runs.

  • Adds WebViewInspectorTeardown (@MainActor enum) with closeInspector(for:) and closeAllInspectors(in:) helpers wired into BrowserPanel.close(), BrowserPopupWindowController delegate methods, and all applicationShouldTerminate early-exit paths plus applicationWillTerminate.
  • Regression coverage is added via two @MainActor unit tests that assert closeCount == 1 synchronously before the main close cascade, exercising both the pane-close and window-close paths.

Confidence Score: 5/5

Safe to merge; the fix is narrowly scoped to closing the inspector synchronously before every window/pane/app teardown path and does not change any other AppKit or WebKit interaction.

All three teardown entry points (pane, window, app) receive the synchronous close before AppKit begins tearing down; the regression tests verify the critical ordering invariant without timing dependencies on the close-count assertion; no existing lifecycle contracts are modified.

No files require special attention beyond the cosmetic notes on AppDelegate.swift and BrowserPanel.swift.

Important Files Changed

Filename Overview
Sources/Panels/BrowserPanel.swift Adds closeDeveloperToolsForTeardown() called from BrowserPanel.close() and introduces the new WebViewInspectorTeardown enum with @MainActor isolation; logic is sound with one cosmetic note on the superview traversal root.
Sources/Panels/BrowserPopupWindowController.swift Adds windowShouldClose delegate for the user-initiated path and WebViewInspectorTeardown.closeInspector in windowWillClose as a safety net for programmatic closes; dual coverage is intentional and safe.
Sources/AppDelegate.swift Calls closeAllWebInspectorsBeforeAppTeardown() on all .terminateNow return paths and also unconditionally in applicationWillTerminate, producing a double-close on every normal termination path (second call is a safe no-op, but redundant).
cmuxTests/BrowserConfigTests.swift Adds two @MainActor regression tests verifying synchronous inspector close before teardown; the critical closeCount assertions fire without delays, with spinRunLoopOneTick used only for secondary UI-state settling.

Sequence Diagram

sequenceDiagram
    participant U as User / AppKit
    participant WD as WindowDelegate / AppDelegate
    participant TD as WebViewInspectorTeardown
    participant WK as WebKit (_inspector SPI)
    participant AK as AppKit close cascade

    Note over U,AK: Pane close (BrowserPanel.close)
    U->>WD: close()
    WD->>TD: closeInspector(for: webView)
    TD->>WK: inspector.close() [same runloop turn]
    WK-->>TD: observer unregistered
    WD->>AK: super.close() to windowWillClose
    AK-->>U: window torn down safely

    Note over U,AK: Main-window close (windowShouldClose)
    U->>WD: windowShouldClose
    WD->>TD: closeAllInspectors(in: window)
    TD->>WK: inspector.close() [same runloop turn]
    WK-->>TD: observer unregistered
    WD-->>AK: return true to windowWillClose
    AK-->>U: window torn down safely

    Note over U,AK: App termination
    U->>WD: applicationShouldTerminate
    WD->>TD: closeAllInspectors(in: NSApp.windows)
    TD->>WK: inspector.close() per window
    WK-->>TD: all observers unregistered
    WD-->>U: .terminateNow
    U->>WD: applicationWillTerminate
    WD->>TD: closeAllWebInspectorsBeforeAppTeardown (no-op)
Loading

Reviews (2): Last reviewed commit: "Preserve synchronous inspector teardown ..." | Re-trigger Greptile

Comment on lines +5901 to +5904
enum WebViewInspectorTeardown {
@discardableResult
static func closeAllInspectors(in window: NSWindow) -> Int {
assert(Thread.isMainThread)

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.

P1 The WebViewInspectorTeardown enum enforces main-thread execution through assert(Thread.isMainThread) at runtime, but the multi-window overload closeAllInspectors(in windows: [NSWindow]) has no assertion at all — it only inherits the check from the inner call. Without an @MainActor annotation on the enum, Swift 6 strict concurrency allows any non-isolated context to call these methods without a compiler error. The crash fix's correctness depends on inspector teardown happening synchronously on the main runloop turn; making that a compile-time guarantee rather than a runtime trap aligns with the fix's stated design invariant.

Suggested change
enum WebViewInspectorTeardown {
@discardableResult
static func closeAllInspectors(in window: NSWindow) -> Int {
assert(Thread.isMainThread)
@MainActor
enum WebViewInspectorTeardown {
@discardableResult
static func closeAllInspectors(in window: NSWindow) -> Int {
assert(Thread.isMainThread)

Rule Used: Flag new or materially worsened Swift 6 actor isol... (source)

Comment thread cmuxTests/BrowserConfigTests.swift Outdated
Comment on lines +2144 to +2147
override func setUp() {
super.setUp()
setenv("NSZombieEnabled", "YES", 1)
}

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.

P2 setenv("NSZombieEnabled", "YES", 1) in the instance setUp() runs before every test case in the class and permanently enables zombie mode for the entire test-process lifetime — it cannot be undone once set. The class already has a class setUp() override, which is the correct home for a one-time process-wide setting. Repeated re-activation in the instance setUp() is redundant and signals to future readers that this is per-test scaffolding rather than a deliberate process-level choice, risking confusion about when zombie mode is actually active.

Suggested change
override func setUp() {
super.setUp()
setenv("NSZombieEnabled", "YES", 1)
}
// NSZombieEnabled moved to class setUp() — zombie mode is process-global and
// cannot be unset; activating it once at class setup is the correct scope.
// See override class func setUp() above.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@cmuxTests/BrowserConfigTests.swift`:
- Around line 2195-2207: The test currently advances the run loop before
asserting inspector.closeCount, which permits async teardown; update
testPaneCloseClosesVisibleInspectorSynchronouslyBeforeWebViewTeardown to assert
inspector.closeCount == 1 immediately after calling panel.close() (i.e., add an
immediate XCTAssertEqual(inspector.closeCount, 1) directly after panel.close())
to enforce synchronous behavior, then keep the existing spinRunLoopOneTick() and
subsequent XCTAssertFalse(panel.isDeveloperToolsVisible()) check to verify
post-teardown state.
- Around line 2144-2147: The test currently calls setenv("NSZombieEnabled",
"YES", 1) inside override func setUp(), which is ineffective after process
launch and mutates global state; remove the setenv call from setUp (and any
related teardown) and instead configure NSZombieEnabled as an environment
variable before the process starts (e.g. in the Xcode test scheme or the test
runner environment), ensuring test isolation and reliable zombie detection for
the process; search for setenv("NSZombieEnabled" or usages in setUp/tearDown to
locate and remove the change.

In `@Sources/Panels/BrowserPopupWindowController.swift`:
- Around line 282-285: The programmatic close path skips windowShouldClose(_:)
so inspectors for all webViews in the popup's window are not torn down; update
the closePopup() implementation to explicitly call
WebViewInspectorTeardown.closeAllInspectors(in: panel) (using the same
panel/window passed to panel.close()) before invoking panel.close(), ensuring
the same semantics as windowShouldClose(_:). Keep windowWillClose(_:)'s
closeInspector(for:) intact as a per-webView fallback.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 86f8ad28-350d-4367-aa85-7bb7daf9693a

📥 Commits

Reviewing files that changed from the base of the PR and between 9b4b0d3 and 228390f.

📒 Files selected for processing (4)
  • Sources/AppDelegate.swift
  • Sources/Panels/BrowserPanel.swift
  • Sources/Panels/BrowserPopupWindowController.swift
  • cmuxTests/BrowserConfigTests.swift

Comment thread cmuxTests/BrowserConfigTests.swift Outdated
Comment thread cmuxTests/BrowserConfigTests.swift
Comment thread Sources/Panels/BrowserPopupWindowController.swift

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 228390f. Configure here.

Comment thread cmuxTests/BrowserConfigTests.swift Outdated
Review feedback exposed two gaps around the teardown contract: the regression allowed a runloop turn before observing the close, and popup programmatic closes could bypass windowShouldClose. This tightens the test to assert the close immediately, routes closePopup through the shared inspector teardown path, removes an ineffective runtime NSZombie environment mutation, and makes the helper main-actor isolated so the compiler preserves the UI-thread boundary.

Constraint: WebKit inspector teardown must complete before AppKit starts host window teardown.

Rejected: Rely on windowShouldClose for popup closePopup | panel.close skips that delegate path.

Confidence: high

Scope-risk: narrow

Tested: git diff --check

Tested: ./scripts/reload.sh --tag issue3828-reviewfix

Tested: ./scripts/reload.sh --tag issue3828-reviewfix --launch

Tested: Manual tagged app repro with Web Inspector open, parent close leaves no inspector window and no new DiagnosticReports crash.

Not-tested: Local cmux-unit run per repo testing policy; CI must rerun on pushed commit.

This branch was successfully deployed

1 active deployment
Preview – cmux — e1c31b8d Deployed May 11, 2026 by vercel[bot]
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.

Crash on closing window/pane after using Web Inspector — UAF in -[WKWebInspectorUIProxyObjCAdapter inspectorViewControllerDidBecomeActive:]

1 participant