diff --git a/chrome/browser/ui/views/autofill/popup/popup_base_view.cc b/chrome/browser/ui/views/autofill/popup/popup_base_view.cc index 269b903884504..6742baf7d4ef0 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_base_view.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_base_view.cc @@ -48,6 +48,7 @@ #include "ui/views/focus/focus_manager.h" #include "ui/views/layout/fill_layout.h" #include "ui/views/layout/layout_provider.h" +#include "ui/views/view_tracker.h" #include "ui/views/widget/widget.h" #if DCHECK_IS_ON() @@ -361,6 +362,11 @@ void PopupBaseView::DoHide() { } void PopupBaseView::NotifyAXSelection(views::View& selected_view) { + // Firing a native accessibility event can synchronously re-enter the browser + // UI thread (e.g. on Windows, ::UiaRaiseAutomationEvent pumps the COM STA + // and may dispatch pending UI-thread tasks). Guard against `selected_view` + // being destroyed during that re-entrancy. + views::ViewTracker selected_view_tracker(&selected_view); if (!is_ax_menu_start_event_fired_) { // Fire the menu start event once, right before the first item is selected. // By firing these and the matching kMenuEnd events, we are telling screen @@ -372,6 +378,9 @@ void PopupBaseView::NotifyAXSelection(views::View& selected_view) { is_ax_menu_start_event_fired_ = true; } + if (!selected_view_tracker.view()) { + return; + } selected_view.GetViewAccessibility().SetPopupFocusOverride(); #if DCHECK_IS_ON() constexpr auto kDerivedClasses = base::MakeFixedFlatSet( diff --git a/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc b/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc index d01d6ea066df3..4c540673727e2 100644 --- a/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc +++ b/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc @@ -41,6 +41,7 @@ #include "ui/views/layout/box_layout.h" #include "ui/views/metadata/view_factory.h" #include "ui/views/vector_icons.h" +#include "ui/views/view_tracker.h" #include "ui/views/widget/widget.h" namespace { @@ -365,11 +366,19 @@ void PasswordGenerationPopupViewViews::ButtonSelectionUpdated() { auto* nudge_password_buttons = static_cast(nudge_password_buttons_view_); + // NotifyAXSelection() fires native accessibility events which on Windows can + // synchronously pump the COM STA and re-enter the browser UI thread. A + // reentrant Show(kEditGeneratedPassword) -> UpdateState() -> + // RemoveAllChildViews() can free `nudge_password_buttons` mid-call. + views::ViewTracker buttons_tracker(nudge_password_buttons); if (controller_->accept_button_selected()) { NotifyAXSelection(*nudge_password_buttons->GetAcceptButton()); } else if (controller_->cancel_button_selected()) { NotifyAXSelection(*nudge_password_buttons->GetCancelButton()); } + if (!buttons_tracker.view()) { + return; + } nudge_password_buttons->UpdateFocus(controller_->accept_button_selected()); }