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