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