VerteDinde

#51900: fix: emit render-process-gone outside the process-death notification

Merged
Created: Jun 5, 2026, 5:21:40 PM
Merged: Jun 8, 2026, 12:20:10 PM
4 comments
Target: main

Description of Change

Fixes a browser-process crash (CHECK failure in extensions::RendererStartupHelper::OnRenderProcessLaunched, surfacing as EXC_BREAKPOINT on macOS / EXCEPTION_BREAKPOINT on Windows on the CrBrowserMain thread) that occurs when an app reacts synchronously to the render-process-gone event, most commonly by calling webContents.reload() from the handler.

render-process-gone was emitted synchronously from WebContents::PrimaryMainFrameRenderProcessGone, which is invoked while RenderProcessHostImpl::ProcessDied() is still iterating the host's observer list. A reload (or any navigation) from the handler re-enters RenderProcessHostImpl::Init() from inside that loop; the resulting OnRenderProcessHostCreated() dispatch is ignored by RendererStartupHelper because the stale registration from the previous renderer is still present, the helper then untracks the process when its own RenderProcessExited() runs, and when the relaunched process finishes launching, OnRenderProcessLaunched() finds no registration and the CHECK brings down the browser process.

Per review feedback, this no longer touches the upstream CHECK (originally a patches/chromium change). Instead, the render-process-gone emit is deferred by one task, so the process-death notification fully unwinds before app code can react — covering reload(), loadURL(), window recreation, and any other synchronous reaction. Chromium relaxed the same CHECK for this race on Android (https://crrev.com/c/7330559) and ChromeOS (https://crrev.com/c/7862000, https://crbug.com/512916518); extending that to desktop platforms will be pursued upstream separately, since a content-internal path to the same re-entrancy exists that embedder-side deferral cannot reach.

Two intentional behavior notes for review:

  • The event now fires one task later than before. The exitCode is captured at observer time, so the reported details are unchanged.
  • If the WebContents is destroyed within that one-task window, the event is not emitted (the JS wrapper is gone; destroyed fires as usual).

Verified locally on macOS (arm64) with the CHECK intact: a standalone repro (synchronous reload() inside render-process-gone + forcefullyCrashRenderer()) reliably crashes an unpatched build of main with FATAL:extensions/browser/renderer_startup_helper.cc:285] Check failed: GetRenderer(host) != nullptr || !client->IsSameContext(...), and survives with the deferred emit (reload completes normally). The added regression spec exercises the same sequence.

Checklist

Release Notes

Notes: Fixed a browser process crash when calling webContents.reload() or navigating synchronously from the render-process-gone event; the event is now emitted after the renderer's teardown notification has completed.

Backports

41-x-y
In-flight
PR Number
#51917
Waiting to be merged
42-x-y
Merged
PR Number
#51916
Merged At
Jun 8, 2026, 3:06:00 PM
Released In
v42.4.0
Release Date
Jun 9, 2026, 1:06:27 AM
43-x-y
Merged
PR Number
#51918
Merged At
Jun 8, 2026, 3:05:15 PM
Released In
Not yet
Release Date
Not yet

Semver Impact

Major
Breaking changes
Minor
New features
Patch
Bug fixes
None
Docs, tests, etc.

Semantic Versioning helps users understand the impact of updates:

  • Major (X.y.z): Breaking changes that may require code modifications
  • Minor (x.Y.z): New features that maintain backward compatibility
  • Patch (x.y.Z): Bug fixes that don't change the API
  • None: Changes that don't affect using facing parts of Electron