Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2021 The Chromium Authors |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 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_MEMORY_SAFE_REF_H_ |
| 6 | #define BASE_MEMORY_SAFE_REF_H_ |
| 7 | |
| 8 | #include "base/check.h" |
Paul Semel | 5eac04a1 | 2023-06-07 18:17:32 | [diff] [blame^] | 9 | #include "base/memory/safe_ref_traits.h" |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 10 | #include "base/memory/weak_ptr.h" |
| 11 | |
| 12 | #include <utility> |
| 13 | |
| 14 | namespace base { |
| 15 | |
| 16 | // SafeRef smart pointers are used to represent a non-owning pointer to an |
| 17 | // object, where the pointer is always intended to be valid. These are useful in |
| 18 | // the same cases that a raw pointer `T*` (or a `T&`) would traditionally be |
| 19 | // used, as the owner of the SafeRef knows the lifetime of the pointed-to object |
| 20 | // from other means and will not use the pointer after the pointed-to object is |
| 21 | // destroyed. However, unlike a `T*` or `T&`, a logic bug will manifest as a |
| 22 | // benign crash instead of as a Use-after-Free. |
| 23 | // |
| 24 | // SafeRef pointers can not be null (as expressed by the "Ref" suffix instead of |
| 25 | // "Ptr"). A SafeRef can be wrapped in an absl::optional if it should not always |
| 26 | // point to something valid. (A SafePtr sibling type can be introduced if this |
| 27 | // is problematic, or if consuming moves are needed!) |
| 28 | // |
| 29 | // If code wants to track the lifetime of the object directly through its |
| 30 | // pointer, and dynamically handle the case of the pointer outliving the object |
| 31 | // it points to, then base::WeakPtr should be used instead. |
| 32 | // |
| 33 | // The SafeRef pointer is constructed from a base::WeakPtrFactory's GetSafeRef() |
| 34 | // method. Since it is tied to the base::WeakPtrFactory, it will consider its |
| 35 | // pointee invalid when the base::WeakPtrFactory is invalidated, in the same way |
| 36 | // as base::WeakPtr does, including after a call to InvalidateWeakPtrs(). |
| 37 | // |
Paul Semel | 5eac04a1 | 2023-06-07 18:17:32 | [diff] [blame^] | 38 | // SafeRefTraits are only meant to mark SafeRef that were found to be dangling, |
| 39 | // thus one should not use this flag to disable dangling pointer detection on |
| 40 | // SafeRef. This parameter is set to SafeRefTraits::kEmpty by default. |
| 41 | // |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 42 | // THREAD SAFETY: SafeRef pointers (like base::WeakPtr) may only be used on the |
| 43 | // sequence (or thread) where the associated base::WeakPtrFactory will be |
| 44 | // invalidated and/or destroyed. They are safe to passively hold or to destroy |
| 45 | // on any thread though. |
| 46 | // |
| 47 | // This class is expected to one day be replaced by a more flexible and safe |
| 48 | // smart pointer abstraction which is not tied to base::WeakPtrFactory, such as |
| 49 | // raw_ptr<T> from the MiraclePtr project (though perhaps a non-nullable raw_ref |
| 50 | // equivalent). |
Paul Semel | 5eac04a1 | 2023-06-07 18:17:32 | [diff] [blame^] | 51 | template <typename T, SafeRefTraits Traits /*= SafeRefTraits::kEmpty*/> |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 52 | class SafeRef { |
| 53 | public: |
| 54 | // No default constructor, since there's no null state. Use an optional |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 55 | // SafeRef if the pointer may not be present. |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 56 | |
| 57 | // Copy construction and assignment. |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 58 | SafeRef(const SafeRef& other) : ref_(other.ref_), ptr_(other.ptr_) { |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 59 | // Avoid use-after-move. |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 60 | CHECK(ref_.IsValid()); |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 61 | } |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 62 | SafeRef& operator=(const SafeRef& other) { |
| 63 | ref_ = other.ref_; |
| 64 | ptr_ = other.ptr_; |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 65 | // Avoid use-after-move. |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 66 | CHECK(ref_.IsValid()); |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 67 | return *this; |
| 68 | } |
| 69 | |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 70 | // Move construction and assignment. |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 71 | SafeRef(SafeRef&& other) |
| 72 | : ref_(std::move(other.ref_)), ptr_(std::move(other.ptr_)) { |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 73 | // Avoid use-after-move. |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 74 | CHECK(ref_.IsValid()); |
| 75 | } |
| 76 | SafeRef& operator=(SafeRef&& other) { |
| 77 | ref_ = std::move(other.ref_); |
| 78 | ptr_ = std::move(other.ptr_); |
| 79 | // Avoid use-after-move. |
| 80 | CHECK(ref_.IsValid()); |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 81 | return *this; |
| 82 | } |
| 83 | |
| 84 | // Copy conversion from SafeRef<U>. |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 85 | template <typename U, |
| 86 | typename = std::enable_if_t<std::is_convertible_v<U*, T*>>> |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 87 | // NOLINTNEXTLINE(google-explicit-constructor) |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 88 | SafeRef(const SafeRef<U>& other) |
| 89 | : ref_(other.ref_), |
| 90 | ptr_(other.ptr_) // raw_ptr<U> converts to raw_ptr<T>. |
| 91 | { |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 92 | // Avoid use-after-move. |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 93 | CHECK(ref_.IsValid()); |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 94 | } |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 95 | template <typename U> |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 96 | SafeRef& operator=(const SafeRef<U>& other) { |
| 97 | ref_ = other.ref_; |
| 98 | ptr_ = other.ptr_; // raw_ptr<U> converts to raw_ptr<T>. |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 99 | // Avoid use-after-move. |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 100 | CHECK(ref_.IsValid()); |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 101 | return *this; |
| 102 | } |
| 103 | |
| 104 | // Move conversion from SafeRef<U>. |
| 105 | template <typename U> |
| 106 | // NOLINTNEXTLINE(google-explicit-constructor) |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 107 | SafeRef(SafeRef<U>&& other) |
| 108 | : ref_(std::move(other.ref_)), |
| 109 | ptr_(std::move(other.ptr_)) // raw_ptr<U> converts to raw_ptr<T>. |
| 110 | { |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 111 | // Avoid use-after-move. |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 112 | CHECK(ref_.IsValid()); |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 113 | } |
| 114 | template <typename U> |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 115 | SafeRef& operator=(SafeRef<U>&& other) { |
| 116 | ref_ = std::move(other.ref_); |
| 117 | ptr_ = std::move(other.ptr_); // raw_ptr<U> converts to raw_ptr<T>. |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame] | 118 | // Avoid use-after-move. |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 119 | CHECK(ref_.IsValid()); |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 120 | return *this; |
| 121 | } |
| 122 | |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 123 | // Provide access to the underlying T as a reference. Will CHECK() if the T |
| 124 | // pointee is no longer alive. |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 125 | T& operator*() const { |
| 126 | CHECK(ref_.IsValid()); |
| 127 | return *ptr_; |
| 128 | } |
| 129 | |
| 130 | // Used to call methods on the underlying T. Will CHECK() if the T pointee is |
| 131 | // no longer alive. |
| 132 | T* operator->() const { |
| 133 | CHECK(ref_.IsValid()); |
| 134 | return &*ptr_; |
| 135 | } |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 136 | |
| 137 | private: |
Paul Semel | 5eac04a1 | 2023-06-07 18:17:32 | [diff] [blame^] | 138 | template <typename U, SafeRefTraits PassedTraits> |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 139 | friend class SafeRef; |
Stephan Hartmann | a951ccf7 | 2021-10-06 18:06:31 | [diff] [blame] | 140 | template <typename U> |
| 141 | friend SafeRef<U> internal::MakeSafeRefFromWeakPtrInternals( |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 142 | internal::WeakReference&& ref, |
Stephan Hartmann | a951ccf7 | 2021-10-06 18:06:31 | [diff] [blame] | 143 | U* ptr); |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 144 | |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 145 | // Construction from a from a WeakPtr's internals. Will CHECK() if the WeakPtr |
| 146 | // is already invalid. |
| 147 | explicit SafeRef(internal::WeakReference&& ref, T* ptr) |
| 148 | : ref_(std::move(ref)), ptr_(ptr) { |
| 149 | CHECK(ref_.IsValid()); |
| 150 | } |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 151 | |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 152 | internal::WeakReference ref_; |
| 153 | |
Paul Semel | 5eac04a1 | 2023-06-07 18:17:32 | [diff] [blame^] | 154 | static constexpr RawPtrTraits PtrTrait = Traits == SafeRefTraits::kEmpty |
| 155 | ? RawPtrTraits::kEmpty |
| 156 | : DanglingUntriaged; |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 157 | // This pointer is only valid when ref_.is_valid() is true. Otherwise, its |
| 158 | // value is undefined (as opposed to nullptr). Unlike WeakPtr, this raw_ptr is |
| 159 | // not allowed to dangle. |
Paul Semel | 5eac04a1 | 2023-06-07 18:17:32 | [diff] [blame^] | 160 | raw_ptr<T, PtrTrait> ptr_; |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 161 | }; |
| 162 | |
| 163 | namespace internal { |
| 164 | template <typename T> |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 165 | SafeRef<T> MakeSafeRefFromWeakPtrInternals(internal::WeakReference&& ref, |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 166 | T* ptr) { |
danakj | cfcdfb7a | 2023-02-23 01:05:35 | [diff] [blame] | 167 | return SafeRef<T>(std::move(ref), ptr); |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 168 | } |
| 169 | } // namespace internal |
| 170 | |
| 171 | } // namespace base |
| 172 | |
| 173 | #endif // BASE_MEMORY_SAFE_REF_H_ |