1 // Copyright 2018 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_OBSERVER_LIST_INTERNAL_H_ 6 #define BASE_OBSERVER_LIST_INTERNAL_H_ 7 8 #include <string> 9 10 #include "base/base_export.h" 11 #include "base/check.h" 12 #include "base/containers/linked_list.h" 13 #include "base/dcheck_is_on.h" 14 #include "base/memory/raw_ptr.h" 15 #include "base/memory/raw_ptr_exclusion.h" 16 #include "base/memory/weak_ptr.h" 17 #include "base/observer_list_types.h" 18 19 #if DCHECK_IS_ON() 20 #include "base/debug/stack_trace.h" 21 #endif 22 23 namespace base { 24 namespace internal { 25 26 // Adapter for putting raw pointers into an ObserverList<Foo>::Unchecked. 27 class BASE_EXPORT UncheckedObserverAdapter { 28 public: UncheckedObserverAdapter(const void * observer)29 explicit UncheckedObserverAdapter(const void* observer) 30 : ptr_(const_cast<void*>(observer)) {} 31 UncheckedObserverAdapter(const UncheckedObserverAdapter&) = delete; 32 UncheckedObserverAdapter& operator=(const UncheckedObserverAdapter&) = delete; 33 UncheckedObserverAdapter(UncheckedObserverAdapter&& other) = default; 34 UncheckedObserverAdapter& operator=(UncheckedObserverAdapter&& other) = 35 default; 36 MarkForRemoval()37 void MarkForRemoval() { ptr_ = nullptr; } 38 IsMarkedForRemoval()39 bool IsMarkedForRemoval() const { return !ptr_; } IsEqual(const void * rhs)40 bool IsEqual(const void* rhs) const { return ptr_ == rhs; } 41 42 template <class ObserverType> Get(const UncheckedObserverAdapter & adapter)43 static ObserverType* Get(const UncheckedObserverAdapter& adapter) { 44 static_assert( 45 !std::is_base_of_v<CheckedObserver, ObserverType>, 46 "CheckedObserver classes must not use ObserverList<T>::Unchecked."); 47 return static_cast<ObserverType*>(adapter.ptr_); 48 } 49 50 #if DCHECK_IS_ON() GetCreationStackString()51 std::string GetCreationStackString() const { 52 return "Observer created at:\n" + stack_.ToString(); 53 } 54 #endif // DCHECK_IS_ON() 55 56 private: 57 raw_ptr<void, AcrossTasksDanglingUntriaged> ptr_; 58 #if DCHECK_IS_ON() 59 base::debug::StackTrace stack_; 60 #endif // DCHECK_IS_ON() 61 }; 62 63 // Adapter for CheckedObserver types so that they can use the same syntax as a 64 // raw pointer when stored in the std::vector of observers in an ObserverList. 65 // It wraps a WeakPtr<CheckedObserver> and allows a "null" pointer via 66 // destruction to be distinguished from an observer marked for deferred removal 67 // whilst an iteration is in progress. 68 class BASE_EXPORT CheckedObserverAdapter { 69 public: 70 explicit CheckedObserverAdapter(const CheckedObserver* observer); 71 72 // Move-only construction and assignment is required to store this in STL 73 // types. 74 CheckedObserverAdapter(CheckedObserverAdapter&& other); 75 CheckedObserverAdapter& operator=(CheckedObserverAdapter&& other); 76 CheckedObserverAdapter(const CheckedObserverAdapter&) = delete; 77 CheckedObserverAdapter& operator=(const CheckedObserverAdapter&) = delete; 78 ~CheckedObserverAdapter(); 79 MarkForRemoval()80 void MarkForRemoval() { 81 DCHECK(weak_ptr_); 82 weak_ptr_ = nullptr; 83 } 84 IsMarkedForRemoval()85 bool IsMarkedForRemoval() const { 86 // If |weak_ptr_| was invalidated then this attempt to iterate over the 87 // pointer is a UAF. Tip: If it's unclear where the `delete` occurred, try 88 // adding CHECK(!IsInObserverList()) to the ~CheckedObserver() (destructor) 89 // override. However, note that this is not always a bug: a destroyed 90 // observer can exist in an ObserverList so long as nothing iterates over 91 // the ObserverList before the list itself is destroyed. 92 CHECK(!weak_ptr_.WasInvalidated()); 93 return weak_ptr_ == nullptr; 94 } 95 IsEqual(const CheckedObserver * rhs)96 bool IsEqual(const CheckedObserver* rhs) const { 97 // Note that inside an iteration, ObserverList::HasObserver() may call this 98 // and |weak_ptr_| may be null due to a deferred removal, which is fine. 99 return weak_ptr_.get() == rhs; 100 } 101 102 template <class ObserverType> Get(const CheckedObserverAdapter & adapter)103 static ObserverType* Get(const CheckedObserverAdapter& adapter) { 104 static_assert( 105 std::is_base_of_v<CheckedObserver, ObserverType>, 106 "Observers should inherit from base::CheckedObserver. " 107 "Use ObserverList<T>::Unchecked to observe with raw pointers."); 108 DCHECK(adapter.weak_ptr_); 109 return static_cast<ObserverType*>(adapter.weak_ptr_.get()); 110 } 111 112 #if DCHECK_IS_ON() GetCreationStackString()113 std::string GetCreationStackString() const { return stack_.ToString(); } 114 #endif 115 116 private: 117 WeakPtr<CheckedObserver> weak_ptr_; 118 #if DCHECK_IS_ON() 119 base::debug::StackTrace stack_; 120 #endif 121 }; 122 123 // Wraps a pointer in a stack-allocated, base::LinkNode. The node is 124 // automatically removed from the linked list upon destruction (of the node, not 125 // the pointer). Nodes are detached from the list via Invalidate() in the 126 // destructor of ObserverList. This invalidates all WeakLinkNodes. There is no 127 // threading support. 128 template <class ObserverList> 129 class WeakLinkNode : public base::LinkNode<WeakLinkNode<ObserverList>> { 130 public: 131 WeakLinkNode() = default; WeakLinkNode(ObserverList * list)132 explicit WeakLinkNode(ObserverList* list) { SetList(list); } 133 WeakLinkNode(const WeakLinkNode&) = delete; 134 WeakLinkNode& operator=(const WeakLinkNode&) = delete; 135 ~WeakLinkNode()136 ~WeakLinkNode() { Invalidate(); } 137 IsOnlyRemainingNode()138 bool IsOnlyRemainingNode() const { 139 return list_ && 140 list_->live_iterators_.head() == list_->live_iterators_.tail(); 141 } 142 SetList(ObserverList * list)143 void SetList(ObserverList* list) { 144 DCHECK(!list_); 145 DCHECK(list); 146 list_ = list; 147 list_->live_iterators_.Append(this); 148 } 149 Invalidate()150 void Invalidate() { 151 if (list_) { 152 list_ = nullptr; 153 this->RemoveFromList(); 154 } 155 } 156 get()157 ObserverList* get() const { 158 if (list_) 159 DCHECK_CALLED_ON_VALID_SEQUENCE(list_->iteration_sequence_checker_); 160 return list_; 161 } 162 ObserverList* operator->() const { return get(); } 163 explicit operator bool() const { return get(); } 164 165 private: 166 // `list_` is not a raw_ptr<...> for performance reasons: on-stack pointer + 167 // based on analysis of sampling profiler data and tab_search:top100:2020. 168 RAW_PTR_EXCLUSION ObserverList* list_ = nullptr; 169 }; 170 171 } // namespace internal 172 } // namespace base 173 174 #endif // BASE_OBSERVER_LIST_INTERNAL_H_ 175