Skip to content

[Bug]: desktop hard-crashes (SIGSEGV) from preview CDP sessions — Electron webContents.debugger use-after-free (upstream electron#53376) #9067

Description

@sethwebster

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/desktop

Steps to reproduce

No deterministic repro — the crash is GC-timing dependent. Conditions that produce it (hit 3 times in one day on macOS):

  1. Use preview automation heavily (agent-driven preview_* MCP tools), so PreviewManager.ensureControlSession attaches wc.debugger.attach("1.3") to preview webview guests with Runtime/Accessibility/Network/Log enabled (constant CDP notification stream).
  2. Close / recreate preview tabs so webview guest WebContents get destroyed while a control session is (or was recently) attached.
  3. Keep the app running; the browser process segfaults minutes to tens of minutes later, on the next GC cycle that sweeps a still-attached Debugger wrapper.

Expected behavior

Preview automation sessions attach and detach CDP debuggers without ever being able to take down the desktop app, regardless of tab close timing or GC.

Actual behavior

Hard crash (SIGSEGV, KERN_INVALID_ADDRESS at 0x10/0x18) of the entire desktop app on CrBrowserMain. Three crashes on 2026-09-01 (11:18, 12:11, 12:56 EDT) across two nightlies (0.0.38-nightly.20260831.1236 on Electron 41.5.0 and 0.0.38-nightly.20260901.1246 on Electron 43.4.1), so it is not fixed by the Electron bump.

Root cause is an upstream Electron use-after-free, reported by us as electron/electron#53376: electron::api::Debugger is cppgc/Oilpan-managed but registers with content as a raw DevToolsAgentHostClient*, and ~Debugger() never calls agent_host_->DetachClient(this). When GC sweeps a still-attached Debugger, the DevTools session keeps a dangling client pointer; the next inbound CDP notification (2 of 3 crashes) or a WebContents-tree teardown running ForceDetachAllSessionsImpl (1 of 3) dispatches into freed memory.

T3's exposure comes from apps/desktop/src/preview/Manager.ts (ensureControlSession, ~line 1100):

  • The detach lives in an async Effect scope finalizer, which can run after the native WebContents is already destroyed — so webview guests routinely die with the debugger still attached (the exact precondition for the upstream bug).
  • Nothing pins the wc.debugger JS wrapper for the session's lifetime; once the guest's api::WebContents wrapper goes away, the attached Debugger is garbage and gets swept.

Proposed hardening until the upstream fix ships (either alone likely suffices; both is cheap):

  1. Detach the control session's debugger synchronously in the webview close/destroyed path, before native teardown — not only in the async scope finalizer.
  2. Hold a strong reference to wc.debugger in the BrowserControlSession so the wrapper cannot be swept while attached.

Impact

Major degradation or frequent failure

Version or commit

0.0.38-nightly.20260831.1236 (Electron 41.5.0) and 0.0.38-nightly.20260901.1246 (Electron 43.4.1)

Environment

macOS 26.6.2, arm64. Desktop app, local environment, heavy preview automation via MCP.

Logs or stack traces

# Signature A (crashes at 12:11 and 12:56) — CDP notification to freed client
# symbolicated from .ips imageOffsets against Electron breakpad symbols
0  content::DevToolsSession::DispatchProtocolNotification(...)
1  blink::mojom::DevToolsSessionHostStubDispatch::Accept(...)
2  mojo::InterfaceEndpointClient::HandleIncomingMessageThunk::Accept(mojo::Message*)
3  mojo::InterfaceEndpointClient::HandleIncomingMessage(mojo::Message*)
4  IPC::ChannelAssociatedGroupController::AcceptOnEndpointThread(...)
5  base::TaskAnnotator::RunTaskImpl(base::PendingTask&)
   ... message pump / CFRunLoop ...

# Signature B (crash at 11:18) — teardown force-detach into freed client
0  content::DevToolsAgentHostImpl::ForceDetachAllSessionsImpl()
1  content::RenderFrameDevToolsAgentHost::DestroyOnRenderFrameGone()
2  content::RenderFrameDevToolsAgentHost::FrameDeleted(...)
3  content::WebContentsImpl::OnFrameTreeNodeDestroyed(...)
4  content::FrameTree::Shutdown()
5  content::WebContentsImpl::~WebContentsImpl()
6  content::WebContentsImpl::WebContentsTreeNode::DestroyOwnedInnerWebContents(...)
   ...
14 electron::InspectableWebContents::~InspectableWebContents()
15 electron::api::WebContents::~WebContents()
16 electron::api::WebContents::DeleteThisIfAlive()

# Full macOS .ips reports available on request.

Workaround

None at runtime. Avoiding preview automation avoids the crash. Upstream fix tracked in electron/electron#53376.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions