• 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 
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<CheckedObserver, ObserverType>::value,
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 { return stack_.ToString(); }
52 #endif  // DCHECK_IS_ON()
53 
54  private:
55   raw_ptr<void, DanglingUntriaged> ptr_;
56 #if DCHECK_IS_ON()
57   base::debug::StackTrace stack_;
58 #endif  // DCHECK_IS_ON()
59 };
60 
61 // Adapter for CheckedObserver types so that they can use the same syntax as a
62 // raw pointer when stored in the std::vector of observers in an ObserverList.
63 // It wraps a WeakPtr<CheckedObserver> and allows a "null" pointer via
64 // destruction to be distinguished from an observer marked for deferred removal
65 // whilst an iteration is in progress.
66 class BASE_EXPORT CheckedObserverAdapter {
67  public:
68   explicit CheckedObserverAdapter(const CheckedObserver* observer);
69 
70   // Move-only construction and assignment is required to store this in STL
71   // types.
72   CheckedObserverAdapter(CheckedObserverAdapter&& other);
73   CheckedObserverAdapter& operator=(CheckedObserverAdapter&& other);
74   CheckedObserverAdapter(const CheckedObserverAdapter&) = delete;
75   CheckedObserverAdapter& operator=(const CheckedObserverAdapter&) = delete;
76   ~CheckedObserverAdapter();
77 
MarkForRemoval()78   void MarkForRemoval() {
79     DCHECK(weak_ptr_);
80     weak_ptr_ = nullptr;
81   }
82 
IsMarkedForRemoval()83   bool IsMarkedForRemoval() const {
84     // If |weak_ptr_| was invalidated then this attempt to iterate over the
85     // pointer is a UAF. Tip: If it's unclear where the `delete` occurred, try
86     // adding CHECK(!IsInObserverList()) to the ~CheckedObserver() (destructor)
87     // override. However, note that this is not always a bug: a destroyed
88     // observer can exist in an ObserverList so long as nothing iterates over
89     // the ObserverList before the list itself is destroyed.
90     CHECK(!weak_ptr_.WasInvalidated());
91     return weak_ptr_ == nullptr;
92   }
93 
IsEqual(const CheckedObserver * rhs)94   bool IsEqual(const CheckedObserver* rhs) const {
95     // Note that inside an iteration, ObserverList::HasObserver() may call this
96     // and |weak_ptr_| may be null due to a deferred removal, which is fine.
97     return weak_ptr_.get() == rhs;
98   }
99 
100   template <class ObserverType>
Get(const CheckedObserverAdapter & adapter)101   static ObserverType* Get(const CheckedObserverAdapter& adapter) {
102     static_assert(
103         std::is_base_of<CheckedObserver, ObserverType>::value,
104         "Observers should inherit from base::CheckedObserver. "
105         "Use ObserverList<T>::Unchecked to observe with raw pointers.");
106     DCHECK(adapter.weak_ptr_);
107     return static_cast<ObserverType*>(adapter.weak_ptr_.get());
108   }
109 
110 #if DCHECK_IS_ON()
GetCreationStackString()111   std::string GetCreationStackString() const { return stack_.ToString(); }
112 #endif
113 
114  private:
115   WeakPtr<CheckedObserver> weak_ptr_;
116 #if DCHECK_IS_ON()
117   base::debug::StackTrace stack_;
118 #endif
119 };
120 
121 // Wraps a pointer in a stack-allocated, base::LinkNode. The node is
122 // automatically removed from the linked list upon destruction (of the node, not
123 // the pointer). Nodes are detached from the list via Invalidate() in the
124 // destructor of ObserverList. This invalidates all WeakLinkNodes. There is no
125 // threading support.
126 template <class ObserverList>
127 class WeakLinkNode : public base::LinkNode<WeakLinkNode<ObserverList>> {
128  public:
129   WeakLinkNode() = default;
WeakLinkNode(ObserverList * list)130   explicit WeakLinkNode(ObserverList* list) { SetList(list); }
131   WeakLinkNode(const WeakLinkNode&) = delete;
132   WeakLinkNode& operator=(const WeakLinkNode&) = delete;
133 
~WeakLinkNode()134   ~WeakLinkNode() { Invalidate(); }
135 
IsOnlyRemainingNode()136   bool IsOnlyRemainingNode() const {
137     return list_ &&
138            list_->live_iterators_.head() == list_->live_iterators_.tail();
139   }
140 
SetList(ObserverList * list)141   void SetList(ObserverList* list) {
142     DCHECK(!list_);
143     DCHECK(list);
144     list_ = list;
145     list_->live_iterators_.Append(this);
146   }
147 
Invalidate()148   void Invalidate() {
149     if (list_) {
150       list_ = nullptr;
151       this->RemoveFromList();
152     }
153   }
154 
get()155   ObserverList* get() const {
156     if (list_)
157       DCHECK_CALLED_ON_VALID_SEQUENCE(list_->iteration_sequence_checker_);
158     return list_;
159   }
160   ObserverList* operator->() const { return get(); }
161   explicit operator bool() const { return get(); }
162 
163  private:
164   // `list_` is not a raw_ptr<...> for performance reasons: on-stack pointer +
165   // based on analysis of sampling profiler data and tab_search:top100:2020.
166   RAW_PTR_EXCLUSION ObserverList* list_ = nullptr;
167 };
168 
169 }  // namespace internal
170 }  // namespace base
171 
172 #endif  // BASE_OBSERVER_LIST_INTERNAL_H_
173