ckerr

#52546: fix: dangling rawptr NativeWindow::primary_web_contents_view_

Merged
Created: Jul 29, 2026, 7:28:29 PM
Merged: Jul 30, 2026, 7:13:37 PM
3 comments
Target: main

Description of Change

Fix a dangling raw_ptr in NativeWindow::primary_web_contents_view_ after the electron::api::WebContents was destroyed.

When looking at this, I noticed that NativeWindow::set_primary_web_contents_view() was used for only two things: (1) initializing the value on startup (one callsite) (2) clearing the value when the WebContentsView was being torn down (two callsites). Following that pattern, the fix for this crash would be to add a third set_rimary_web_contents_view(nullptr) call, this time in WebContents::~WebContents().

This duplicated manual pointer management is a code smell. Instead of adding a third call, I've removed the method and changed the field's type so that ui::Views can track the view's lifecycle for us:

-  raw_ptr<InspectableWebContentsView> primary_web_contents_view_ = nullptr;
+  views::ViewTracker primary_web_contents_view_;

The rawptr bug that this fixes was showing up in:

  1. default behavior window-all-closed quits when the app does not handle the event
  2. default behavior window-all-closed does not quit when the app handles the event

and the crash was:

[DanglingSignature]	base::debug::CollectStackTrace() [../../base/debug/stack_trace_posix.cc:1052:7]	electron::api::WebContents::Destroy() [../../electron/shell/browser/api/electron_api_web_contents.cc:1261:9]	electron::NativeWindow::set_primary_web_contents_view() [../../base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ptr_backup_ref_impl.h:194:7]	electron::api::WebContents::Destroy() [../../electron/shell/browser/api/electron_api_web_contents.cc:1261:9]

[DanglingPtr](1/3) A raw_ptr/raw_ref is dangling.

[DanglingPtr](2/3) First, the memory was freed at:

Stack trace:
#0 0x5ffa3a61c242 base::debug::CollectStackTrace() [../../base/debug/stack_trace_posix.cc:1052:7]
#1 0x5ffa3a5feab4 base::debug::StackTrace::StackTrace() [../../base/debug/stack_trace.cc:281:20]
#2 0x5ffa3a626646 base::allocator::(anonymous namespace)::DanglingRawPtrDetected() [../../base/allocator/partition_alloc_support.cc:464:11]
#3 0x5ffa3a6d3c07 partition_alloc::PartitionRoot::FreeInline<>() [../../base/allocator/partition_allocator/src/partition_alloc/in_slot_metadata.h:402:5]
#4 0x5ffa329a2366 electron::InspectableWebContentsView::~InspectableWebContentsView() [../../electron/shell/browser/ui/inspectable_web_contents_view.cc:121:59]
#5 0x5ffa32998357 electron::InspectableWebContents::~InspectableWebContents() [../../third_party/libc++/src/include/__memory/unique_ptr.h:74:5]
#6 0x5ffa3299873e electron::InspectableWebContents::~InspectableWebContents() [../../electron/shell/browser/ui/inspectable_web_contents.cc:355:51]
#7 0x5ffa328801ee electron::api::WebContents::~WebContents() [../../third_party/libc++/src/include/__memory/unique_ptr.h:74:5]
#8 0x5ffa32880acb electron::api::WebContents::DeleteThisIfAlive() [../../electron/shell/browser/api/electron_api_web_contents.cc:1249:3]
#9 0x5ffa32786c31 base::OnceCallback<>::Run() [../../base/functional/callback.h:155:12]
#10 0x5ffa3a547f6f base::TaskAnnotator::RunTaskImpl() [../../base/task/common/task_annotator.cc:229:34]
#11 0x5ffa3a57ff4c base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl() [../../base/task/common/task_annotator.h:114:5]
#12 0x5ffa3a57f35b base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() [../../base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:341:40]
#13 0x5ffa3a647e74 base::MessagePumpGlib::HandleDispatch() [../../base/message_loop/message_pump_glib.cc:732:46]
#14 0x5ffa3a644c7e base::(anonymous namespace)::WorkSourceDispatch() [../../base/message_loop/message_pump_glib.cc:355:43]
#15 0x71b60a36cc7b (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8600.0+0x60c7a)
#16 0x71b60a36e2b7 (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8600.0+0x622b6)
#17 0x71b60a36e4a3 g_main_context_iteration
#18 0x5ffa3a6481ed base::MessagePumpGlib::Run() [../../base/message_loop/message_pump_glib.cc:766:30]
#19 0x5ffa3a580fda base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run() [../../base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:663:12]
#20 0x5ffa3a51e01f base::RunLoop::Run() [../../base/run_loop.cc:135:14]
#21 0x5ffa383322d1 content::BrowserMainLoop::RunMainMessageLoop() [../../content/browser/browser_main_loop.cc:1131:18]
#22 0x5ffa383350e4 content::BrowserMainRunnerImpl::Run() [../../content/browser/browser_main_runner_impl.cc:148:15]
#23 0x5ffa3832d7f2 content::BrowserMain() [../../content/browser/browser_main.cc:32:28]
#24 0x5ffa3307c33e content::RunBrowserProcessMain() [../../content/app/content_main_runner_impl.cc:710:10]
#25 0x5ffa3307fc31 content::ContentMainRunnerImpl::RunBrowser() [../../content/app/content_main_runner_impl.cc:1344:10]
#26 0x5ffa3307eee3 content::ContentMainRunnerImpl::Run() [../../content/app/content_main_runner_impl.cc:1175:12]
#27 0x5ffa3307a3e4 content::RunContentProcess() [../../content/app/content_main.cc:328:36]
#28 0x5ffa3307a5d0 content::ContentMain() [../../content/app/content_main.cc:341:10]
#29 0x5ffa32774b47 main [../../electron/shell/app/electron_main_linux.cc:50:10]
#30 0x71b608ccf575 (/usr/lib/x86_64-linux-gnu/libc.so.6+0x2a574)
#31 0x71b608ccf628 __libc_start_main
#32 0x5ffa3275802a _start

Task trace:
#0 0x5ffa32880be9 electron::api::WebContents::Destroy() [../../electron/shell/browser/api/electron_api_web_contents.cc:1261:9]
#1 0x5ffa32a15101 electron::NodeBindings::WakeupMainThread() [../../electron/shell/common/node_bindings.cc:1162:26]

[DanglingPtr](3/3) Later, the dangling raw_ptr was released at:

Stack trace:
#0 0x5ffa3a61c242 base::debug::CollectStackTrace() [../../base/debug/stack_trace_posix.cc:1052:7]
#1 0x5ffa3a5feab4 base::debug::StackTrace::StackTrace() [../../base/debug/stack_trace.cc:281:20]
#2 0x5ffa3a62672d base::allocator::(anonymous namespace)::DanglingRawPtrReleased<>() [../../base/allocator/partition_alloc_support.cc:626:21]
#3 0x5ffa3a670309 base::internal::RawPtrBackupRefImpl<>::ReleaseInternal() [../../base/allocator/partition_allocator/src/partition_alloc/in_slot_metadata.h:219:7]
#4 0x5ffa327c0801 electron::NativeWindow::set_primary_web_contents_view() [../../base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ptr_backup_ref_impl.h:194:7]
#5 0x5ffa327c0c02 electron::api::BrowserWindow::WebContentsDestroyed() [../../electron/shell/browser/api/electron_api_browser_window.cc:120:13]
#6 0x5ffa38ced9e3 content::WebContentsImpl::WebContentsObserverList::NotifyObservers<>() [../../content/browser/web_contents/web_contents_impl.h:1881:9]
#7 0x5ffa38cebe3d content::WebContentsImpl::~WebContentsImpl() [../../content/browser/web_contents/web_contents_impl.cc:1502:14]
#8 0x5ffa38cedc5e content::WebContentsImpl::~WebContentsImpl() [../../content/browser/web_contents/web_contents_impl.cc:1385:37]
#9 0x5ffa32998557 electron::InspectableWebContents::~InspectableWebContents() [../../third_party/libc++/src/include/__memory/unique_ptr.h:74:5]
#10 0x5ffa3299873e electron::InspectableWebContents::~InspectableWebContents() [../../electron/shell/browser/ui/inspectable_web_contents.cc:355:51]
#11 0x5ffa328801ee electron::api::WebContents::~WebContents() [../../third_party/libc++/src/include/__memory/unique_ptr.h:74:5]
#12 0x5ffa32880acb electron::api::WebContents::DeleteThisIfAlive() [../../electron/shell/browser/api/electron_api_web_contents.cc:1249:3]
#13 0x5ffa32786c31 base::OnceCallback<>::Run() [../../base/functional/callback.h:155:12]
#14 0x5ffa3a547f6f base::TaskAnnotator::RunTaskImpl() [../../base/task/common/task_annotator.cc:229:34]
#15 0x5ffa3a57ff4c base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl() [../../base/task/common/task_annotator.h:114:5]
#16 0x5ffa3a57f35b base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() [../../base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:341:40]
#17 0x5ffa3a647e74 base::MessagePumpGlib::HandleDispatch() [../../base/message_loop/message_pump_glib.cc:732:46]
#18 0x5ffa3a644c7e base::(anonymous namespace)::WorkSourceDispatch() [../../base/message_loop/message_pump_glib.cc:355:43]
#19 0x71b60a36cc7b (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8600.0+0x60c7a)
#20 0x71b60a36e2b7 (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8600.0+0x622b6)
#21 0x71b60a36e4a3 g_main_context_iteration
#22 0x5ffa3a6481ed base::MessagePumpGlib::Run() [../../base/message_loop/message_pump_glib.cc:766:30]
#23 0x5ffa3a580fda base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run() [../../base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:663:12]
#24 0x5ffa3a51e01f base::RunLoop::Run() [../../base/run_loop.cc:135:14]
#25 0x5ffa383322d1 content::BrowserMainLoop::RunMainMessageLoop() [../../content/browser/browser_main_loop.cc:1131:18]
#26 0x5ffa383350e4 content::BrowserMainRunnerImpl::Run() [../../content/browser/browser_main_runner_impl.cc:148:15]
#27 0x5ffa3832d7f2 content::BrowserMain() [../../content/browser/browser_main.cc:32:28]
#28 0x5ffa3307c33e content::RunBrowserProcessMain() [../../content/app/content_main_runner_impl.cc:710:10]
#29 0x5ffa3307fc31 content::ContentMainRunnerImpl::RunBrowser() [../../content/app/content_main_runner_impl.cc:1344:10]
#30 0x5ffa3307eee3 content::ContentMainRunnerImpl::Run() [../../content/app/content_main_runner_impl.cc:1175:12]
#31 0x5ffa3307a3e4 content::RunContentProcess() [../../content/app/content_main.cc:328:36]
#32 0x5ffa3307a5d0 content::ContentMain() [../../content/app/content_main.cc:341:10]
#33 0x5ffa32774b47 main [../../electron/shell/app/electron_main_linux.cc:50:10]
#34 0x71b608ccf575 (/usr/lib/x86_64-linux-gnu/libc.so.6+0x2a574)
#35 0x71b608ccf628 __libc_start_main
#36 0x5ffa3275802a _start

Task trace:
#0 0x5ffa32880be9 electron::api::WebContents::Destroy() [../../electron/shell/browser/api/electron_api_web_contents.cc:1261:9]
#1 0x5ffa32a15101 electron::NodeBindings::WakeupMainThread() [../../electron/shell/common/node_bindings.cc:1162:26]

Please check for more information on:
https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md

Checklist

Release Notes

Notes: none.

Backports

43-x-y
Pending
Waiting for a manual backport
44-x-y
In-flight
PR Number
#52570
Waiting to be merged

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