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