Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(299)

Side by Side Diff: ui/views/focus/focus_manager.cc

Issue 2750633004: Adds code to isolate use-after-free in Views (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/focus/focus_manager.h" 5 #include "ui/views/focus/focus_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/auto_reset.h" 10 #include "base/auto_reset.h"
11 #include "base/debug/alias.h"
12 #include "base/debug/dump_without_crashing.h"
13 #include "base/debug/stack_trace.h"
11 #include "base/logging.h" 14 #include "base/logging.h"
12 #include "ui/base/accelerators/accelerator.h" 15 #include "ui/base/accelerators/accelerator.h"
13 #include "ui/base/ime/input_method.h" 16 #include "ui/base/ime/input_method.h"
14 #include "ui/base/ime/text_input_client.h" 17 #include "ui/base/ime/text_input_client.h"
15 #include "ui/events/event.h" 18 #include "ui/events/event.h"
16 #include "ui/events/keycodes/keyboard_codes.h" 19 #include "ui/events/keycodes/keyboard_codes.h"
17 #include "ui/views/focus/focus_manager_delegate.h" 20 #include "ui/views/focus/focus_manager_delegate.h"
18 #include "ui/views/focus/focus_search.h" 21 #include "ui/views/focus/focus_search.h"
19 #include "ui/views/focus/view_storage.h" 22 #include "ui/views/focus/view_storage.h"
20 #include "ui/views/focus/widget_focus_manager.h" 23 #include "ui/views/focus/widget_focus_manager.h"
21 #include "ui/views/view.h" 24 #include "ui/views/view.h"
22 #include "ui/views/widget/root_view.h" 25 #include "ui/views/widget/root_view.h"
23 #include "ui/views/widget/widget.h" 26 #include "ui/views/widget/widget.h"
24 #include "ui/views/widget/widget_delegate.h" 27 #include "ui/views/widget/widget_delegate.h"
25 28
26 namespace views { 29 namespace views {
30 namespace {
31
32 #if defined(OS_CHROMEOS)
33 // Crash appears to be specific to chromeos, so only log there.
34 bool did_log_focused_view = false;
msw 2017/03/13 18:22:16 optional nit: flip to |should_log_focused_view|?
sky 2017/03/13 19:04:02 Done.
35 #else
36 bool did_log_focused_view = true;
37 #endif
38
39 } // namespace
27 40
28 bool FocusManager::arrow_key_traversal_enabled_ = false; 41 bool FocusManager::arrow_key_traversal_enabled_ = false;
29 42
30 FocusManager::FocusManager(Widget* widget, 43 FocusManager::FocusManager(Widget* widget,
31 std::unique_ptr<FocusManagerDelegate> delegate) 44 std::unique_ptr<FocusManagerDelegate> delegate)
32 : widget_(widget), 45 : widget_(widget),
33 delegate_(std::move(delegate)), 46 delegate_(std::move(delegate)),
34 stored_focused_view_storage_id_( 47 stored_focused_view_storage_id_(
35 ViewStorage::GetInstance()->CreateStorageID()) { 48 ViewStorage::GetInstance()->CreateStorageID()) {
36 DCHECK(widget_); 49 DCHECK(widget_);
37 } 50 }
38 51
39 FocusManager::~FocusManager() { 52 FocusManager::~FocusManager() {
53 if (focused_view_)
54 focused_view_->RemoveObserver(this);
40 } 55 }
41 56
42 bool FocusManager::OnKeyEvent(const ui::KeyEvent& event) { 57 bool FocusManager::OnKeyEvent(const ui::KeyEvent& event) {
43 const int key_code = event.key_code(); 58 const int key_code = event.key_code();
44 59
45 if (event.type() != ui::ET_KEY_PRESSED && event.type() != ui::ET_KEY_RELEASED) 60 if (event.type() != ui::ET_KEY_PRESSED && event.type() != ui::ET_KEY_RELEASED)
46 return false; 61 return false;
47 62
48 if (shortcut_handling_suspended()) 63 if (shortcut_handling_suspended())
49 return true; 64 return true;
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 #endif 336 #endif
322 337
323 // Update the reason for the focus change (since this is checked by 338 // Update the reason for the focus change (since this is checked by
324 // some listeners), then notify all listeners. 339 // some listeners), then notify all listeners.
325 focus_change_reason_ = reason; 340 focus_change_reason_ = reason;
326 for (FocusChangeListener& observer : focus_change_listeners_) 341 for (FocusChangeListener& observer : focus_change_listeners_)
327 observer.OnWillChangeFocus(focused_view_, view); 342 observer.OnWillChangeFocus(focused_view_, view);
328 343
329 View* old_focused_view = focused_view_; 344 View* old_focused_view = focused_view_;
330 focused_view_ = view; 345 focused_view_ = view;
331 if (old_focused_view) 346 if (old_focused_view) {
347 old_focused_view->RemoveObserver(this);
332 old_focused_view->Blur(); 348 old_focused_view->Blur();
349 }
333 // Also make |focused_view_| the stored focus view. This way the stored focus 350 // Also make |focused_view_| the stored focus view. This way the stored focus
334 // view is remembered if focus changes are requested prior to a show or while 351 // view is remembered if focus changes are requested prior to a show or while
335 // hidden. 352 // hidden.
336 SetStoredFocusView(focused_view_); 353 SetStoredFocusView(focused_view_);
337 if (focused_view_) 354 if (focused_view_) {
355 focused_view_->AddObserver(this);
338 focused_view_->Focus(); 356 focused_view_->Focus();
357 if (!did_log_focused_view) {
358 stack_when_focused_view_set_ =
359 base::MakeUnique<base::debug::StackTrace>();
360 }
361 } else {
362 stack_when_focused_view_set_.reset();
363 }
339 364
340 for (FocusChangeListener& observer : focus_change_listeners_) 365 for (FocusChangeListener& observer : focus_change_listeners_)
341 observer.OnDidChangeFocus(old_focused_view, focused_view_); 366 observer.OnDidChangeFocus(old_focused_view, focused_view_);
342 } 367 }
343 368
344 void FocusManager::ClearFocus() { 369 void FocusManager::ClearFocus() {
345 // SetFocusedView(NULL) is going to clear out the stored view to. We need to 370 // SetFocusedView(NULL) is going to clear out the stored view to. We need to
346 // persist it in this case. 371 // persist it in this case.
347 views::View* focused_view = GetStoredFocusView(); 372 views::View* focused_view = GetStoredFocusView();
348 SetFocusedView(NULL); 373 SetFocusedView(NULL);
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 583
559 // |keyboard_accessible_| is only used on Mac. 584 // |keyboard_accessible_| is only used on Mac.
560 #if defined(OS_MACOSX) 585 #if defined(OS_MACOSX)
561 return keyboard_accessible_ ? view->IsAccessibilityFocusable() 586 return keyboard_accessible_ ? view->IsAccessibilityFocusable()
562 : view->IsFocusable(); 587 : view->IsFocusable();
563 #else 588 #else
564 return view->IsAccessibilityFocusable(); 589 return view->IsAccessibilityFocusable();
565 #endif 590 #endif
566 } 591 }
567 592
593 void FocusManager::OnViewIsDeleting(View* view) {
594 CHECK_EQ(view, focused_view_);
595
596 // Widget forwards the appropriate calls such that we should never end up
597 // here. None-the-less crashes indicate we are. This logs the stack once when
598 // this happens.
599 // TODO(sky): remove when cause of 687232 is found.
600 if (stack_when_focused_view_set_ && !did_log_focused_view) {
601 did_log_focused_view = true;
602 size_t stack_size = 0u;
603 const void* const* instruction_pointers =
604 stack_when_focused_view_set_->Addresses(&stack_size);
msw 2017/03/13 18:22:16 q: Could you just store stack_when_focused_view_se
sky 2017/03/13 19:04:01 Indeed. The ToString() representation takes up mor
605 static constexpr size_t kMaxStackSize = 100;
606 const void* instruction_pointers_copy[kMaxStackSize];
607 // Insert markers bracketing the crash to make it easier to locate.
608 instruction_pointers_copy[0] = reinterpret_cast<const void*>(0x12345678);
609 instruction_pointers_copy[std::min(kMaxStackSize - 1, stack_size + 1)] =
610 reinterpret_cast<const void*>(0x12345678);
611 std::memcpy((instruction_pointers_copy + 1), instruction_pointers,
612 std::min(kMaxStackSize - 2, stack_size) * sizeof(const void*));
613 base::debug::Alias(&stack_size);
614 base::debug::Alias(&instruction_pointers_copy);
615 base::debug::DumpWithoutCrashing();
616 stack_when_focused_view_set_.reset();
617 }
618
619 focused_view_->RemoveObserver(this);
620 focused_view_ = nullptr;
msw 2017/03/13 18:22:15 q: Will nulling out |focused_view_| possibly preve
sky 2017/03/13 19:04:02 Yes, that is intentional, especially since this on
621 }
622
568 } // namespace views 623 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698