Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: 206763d22f01385fe58af16174e090139f01f54a [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2018 The Chromium Authors
Trent Apted30f97fd2018-08-21 09:03:472// 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
Sumaid Syed22f60eeb2021-08-26 05:16:268#include <string>
Keren Zhuec64be022024-09-24 06:01:259#include <type_traits>
Sumaid Syed22f60eeb2021-08-26 05:16:2610
Trent Apted30f97fd2018-08-21 09:03:4711#include "base/base_export.h"
David Sanders8cfb63a2022-04-14 19:36:3012#include "base/check.h"
Trent Aptedf59cdf0d32018-10-04 03:42:2213#include "base/containers/linked_list.h"
David Sandersfc1f17fa2022-04-15 00:15:4914#include "base/dcheck_is_on.h"
Sergei Glazunov319a2dd2022-08-31 14:30:1515#include "base/memory/raw_ptr.h"
Keishi Hattori488b7602022-05-02 13:09:3116#include "base/memory/raw_ptr_exclusion.h"
Trent Apted30f97fd2018-08-21 09:03:4717#include "base/memory/weak_ptr.h"
18#include "base/observer_list_types.h"
19
Peter Boström7a4f04c2023-01-10 17:28:4420#if DCHECK_IS_ON()
Marc Treibd29f5d582021-02-23 18:32:5821#include "base/debug/stack_trace.h"
22#endif
23
Trent Apted30f97fd2018-08-21 09:03:4724namespace base {
25namespace internal {
26
27// Adapter for putting raw pointers into an ObserverList<Foo>::Unchecked.
Takashi Sakamoto683a3292024-06-12 09:56:3028template <base::RawPtrTraits ptr_traits = RawPtrTraits::kEmpty,
29 bool use_raw_pointer = false>
Trent Apted30f97fd2018-08-21 09:03:4730class BASE_EXPORT UncheckedObserverAdapter {
31 public:
32 explicit UncheckedObserverAdapter(const void* observer)
33 : ptr_(const_cast<void*>(observer)) {}
David Bienvenu5f4d4f032020-09-27 16:55:0334 UncheckedObserverAdapter(const UncheckedObserverAdapter&) = delete;
35 UncheckedObserverAdapter& operator=(const UncheckedObserverAdapter&) = delete;
Trent Apted30f97fd2018-08-21 09:03:4736 UncheckedObserverAdapter(UncheckedObserverAdapter&& other) = default;
37 UncheckedObserverAdapter& operator=(UncheckedObserverAdapter&& other) =
38 default;
39
40 void MarkForRemoval() { ptr_ = nullptr; }
41
42 bool IsMarkedForRemoval() const { return !ptr_; }
43 bool IsEqual(const void* rhs) const { return ptr_ == rhs; }
44
45 template <class ObserverType>
46 static ObserverType* Get(const UncheckedObserverAdapter& adapter) {
47 static_assert(
Andrew Rayskiy629912382023-10-18 22:58:4248 !std::is_base_of_v<CheckedObserver, ObserverType>,
Trent Apted30f97fd2018-08-21 09:03:4749 "CheckedObserver classes must not use ObserverList<T>::Unchecked.");
50 return static_cast<ObserverType*>(adapter.ptr_);
51 }
52
Peter Boström7a4f04c2023-01-10 17:28:4453#if DCHECK_IS_ON()
Mikel Astizbd772bd2025-05-02 10:16:1054 std::string GetCreationStackString() const { return stack_.ToString(); }
Peter Boström7a4f04c2023-01-10 17:28:4455#endif // DCHECK_IS_ON()
Marc Treibd29f5d582021-02-23 18:32:5856
Trent Apted30f97fd2018-08-21 09:03:4757 private:
Takashi Sakamoto683a3292024-06-12 09:56:3058 using StorageType =
59 std::conditional_t<use_raw_pointer, void*, raw_ptr<void, ptr_traits>>;
60 StorageType ptr_;
Peter Boström7a4f04c2023-01-10 17:28:4461#if DCHECK_IS_ON()
Marc Treibd29f5d582021-02-23 18:32:5862 base::debug::StackTrace stack_;
Peter Boström7a4f04c2023-01-10 17:28:4463#endif // DCHECK_IS_ON()
Trent Apted30f97fd2018-08-21 09:03:4764};
65
66// Adapter for CheckedObserver types so that they can use the same syntax as a
67// raw pointer when stored in the std::vector of observers in an ObserverList.
68// It wraps a WeakPtr<CheckedObserver> and allows a "null" pointer via
69// destruction to be distinguished from an observer marked for deferred removal
70// whilst an iteration is in progress.
71class BASE_EXPORT CheckedObserverAdapter {
72 public:
73 explicit CheckedObserverAdapter(const CheckedObserver* observer);
74
75 // Move-only construction and assignment is required to store this in STL
76 // types.
77 CheckedObserverAdapter(CheckedObserverAdapter&& other);
78 CheckedObserverAdapter& operator=(CheckedObserverAdapter&& other);
David Bienvenu5f4d4f032020-09-27 16:55:0379 CheckedObserverAdapter(const CheckedObserverAdapter&) = delete;
80 CheckedObserverAdapter& operator=(const CheckedObserverAdapter&) = delete;
Trent Apted30f97fd2018-08-21 09:03:4781 ~CheckedObserverAdapter();
82
83 void MarkForRemoval() {
84 DCHECK(weak_ptr_);
Trent Apted453d0b5b2018-08-23 00:13:2285 weak_ptr_ = nullptr;
Trent Apted30f97fd2018-08-21 09:03:4786 }
87
88 bool IsMarkedForRemoval() const {
89 // If |weak_ptr_| was invalidated then this attempt to iterate over the
90 // pointer is a UAF. Tip: If it's unclear where the `delete` occurred, try
91 // adding CHECK(!IsInObserverList()) to the ~CheckedObserver() (destructor)
92 // override. However, note that this is not always a bug: a destroyed
93 // observer can exist in an ObserverList so long as nothing iterates over
94 // the ObserverList before the list itself is destroyed.
95 CHECK(!weak_ptr_.WasInvalidated());
96 return weak_ptr_ == nullptr;
97 }
98
99 bool IsEqual(const CheckedObserver* rhs) const {
100 // Note that inside an iteration, ObserverList::HasObserver() may call this
101 // and |weak_ptr_| may be null due to a deferred removal, which is fine.
102 return weak_ptr_.get() == rhs;
103 }
104
105 template <class ObserverType>
106 static ObserverType* Get(const CheckedObserverAdapter& adapter) {
107 static_assert(
Andrew Rayskiy629912382023-10-18 22:58:42108 std::is_base_of_v<CheckedObserver, ObserverType>,
Trent Apted30f97fd2018-08-21 09:03:47109 "Observers should inherit from base::CheckedObserver. "
110 "Use ObserverList<T>::Unchecked to observe with raw pointers.");
111 DCHECK(adapter.weak_ptr_);
112 return static_cast<ObserverType*>(adapter.weak_ptr_.get());
113 }
114
Peter Boström7a4f04c2023-01-10 17:28:44115#if DCHECK_IS_ON()
Marc Treibd29f5d582021-02-23 18:32:58116 std::string GetCreationStackString() const { return stack_.ToString(); }
117#endif
118
Trent Apted30f97fd2018-08-21 09:03:47119 private:
120 WeakPtr<CheckedObserver> weak_ptr_;
Peter Boström7a4f04c2023-01-10 17:28:44121#if DCHECK_IS_ON()
Marc Treibd29f5d582021-02-23 18:32:58122 base::debug::StackTrace stack_;
123#endif
Trent Apted30f97fd2018-08-21 09:03:47124};
125
Trent Aptedf59cdf0d32018-10-04 03:42:22126// Wraps a pointer in a stack-allocated, base::LinkNode. The node is
127// automatically removed from the linked list upon destruction (of the node, not
128// the pointer). Nodes are detached from the list via Invalidate() in the
129// destructor of ObserverList. This invalidates all WeakLinkNodes. There is no
130// threading support.
131template <class ObserverList>
132class WeakLinkNode : public base::LinkNode<WeakLinkNode<ObserverList>> {
133 public:
134 WeakLinkNode() = default;
135 explicit WeakLinkNode(ObserverList* list) { SetList(list); }
David Bienvenu5f4d4f032020-09-27 16:55:03136 WeakLinkNode(const WeakLinkNode&) = delete;
137 WeakLinkNode& operator=(const WeakLinkNode&) = delete;
Trent Aptedf59cdf0d32018-10-04 03:42:22138
139 ~WeakLinkNode() { Invalidate(); }
140
141 bool IsOnlyRemainingNode() const {
142 return list_ &&
143 list_->live_iterators_.head() == list_->live_iterators_.tail();
144 }
145
146 void SetList(ObserverList* list) {
147 DCHECK(!list_);
148 DCHECK(list);
149 list_ = list;
150 list_->live_iterators_.Append(this);
151 }
152
153 void Invalidate() {
154 if (list_) {
155 list_ = nullptr;
156 this->RemoveFromList();
157 }
158 }
159
160 ObserverList* get() const {
Peter Boström7fbc1382024-04-02 21:48:05161#if EXPENSIVE_DCHECKS_ARE_ON()
Peter Kasting134ef9af2024-12-28 02:30:09162 if (list_) {
Trent Aptedf59cdf0d32018-10-04 03:42:22163 DCHECK_CALLED_ON_VALID_SEQUENCE(list_->iteration_sequence_checker_);
Peter Kasting134ef9af2024-12-28 02:30:09164 }
Peter Boström7fbc1382024-04-02 21:48:05165#endif // EXPENSIVE_DCHECKS_ARE_ON()
Trent Aptedf59cdf0d32018-10-04 03:42:22166 return list_;
167 }
168 ObserverList* operator->() const { return get(); }
169 explicit operator bool() const { return get(); }
170
171 private:
Lukasz Anforowicz877e6222021-11-26 00:03:23172 // `list_` is not a raw_ptr<...> for performance reasons: on-stack pointer +
173 // based on analysis of sampling profiler data and tab_search:top100:2020.
Keishi Hattori488b7602022-05-02 13:09:31174 RAW_PTR_EXCLUSION ObserverList* list_ = nullptr;
Trent Aptedf59cdf0d32018-10-04 03:42:22175};
176
Trent Apted30f97fd2018-08-21 09:03:47177} // namespace internal
178} // namespace base
179
180#endif // BASE_OBSERVER_LIST_INTERNAL_H_