danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 1 | // Copyright (c) 2021 The Chromium Authors. All rights reserved. |
| 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" |
| 9 | #include "base/memory/weak_ptr.h" |
| 10 | |
| 11 | #include <utility> |
| 12 | |
| 13 | namespace base { |
| 14 | |
| 15 | // SafeRef smart pointers are used to represent a non-owning pointer to an |
| 16 | // object, where the pointer is always intended to be valid. These are useful in |
| 17 | // the same cases that a raw pointer `T*` (or a `T&`) would traditionally be |
| 18 | // used, as the owner of the SafeRef knows the lifetime of the pointed-to object |
| 19 | // from other means and will not use the pointer after the pointed-to object is |
| 20 | // destroyed. However, unlike a `T*` or `T&`, a logic bug will manifest as a |
| 21 | // benign crash instead of as a Use-after-Free. |
| 22 | // |
| 23 | // SafeRef pointers can not be null (as expressed by the "Ref" suffix instead of |
| 24 | // "Ptr"). A SafeRef can be wrapped in an absl::optional if it should not always |
| 25 | // point to something valid. (A SafePtr sibling type can be introduced if this |
| 26 | // is problematic, or if consuming moves are needed!) |
| 27 | // |
| 28 | // If code wants to track the lifetime of the object directly through its |
| 29 | // pointer, and dynamically handle the case of the pointer outliving the object |
| 30 | // it points to, then base::WeakPtr should be used instead. |
| 31 | // |
| 32 | // The SafeRef pointer is constructed from a base::WeakPtrFactory's GetSafeRef() |
| 33 | // method. Since it is tied to the base::WeakPtrFactory, it will consider its |
| 34 | // pointee invalid when the base::WeakPtrFactory is invalidated, in the same way |
| 35 | // as base::WeakPtr does, including after a call to InvalidateWeakPtrs(). |
| 36 | // |
| 37 | // THREAD SAFETY: SafeRef pointers (like base::WeakPtr) may only be used on the |
| 38 | // sequence (or thread) where the associated base::WeakPtrFactory will be |
| 39 | // invalidated and/or destroyed. They are safe to passively hold or to destroy |
| 40 | // on any thread though. |
| 41 | // |
| 42 | // This class is expected to one day be replaced by a more flexible and safe |
| 43 | // smart pointer abstraction which is not tied to base::WeakPtrFactory, such as |
| 44 | // raw_ptr<T> from the MiraclePtr project (though perhaps a non-nullable raw_ref |
| 45 | // equivalent). |
| 46 | template <typename T> |
| 47 | class SafeRef { |
| 48 | public: |
| 49 | // No default constructor, since there's no null state. Use an optional |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame^] | 50 | // SafeRef if the pointer may not be present. |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 51 | |
| 52 | // Copy construction and assignment. |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame^] | 53 | SafeRef(const SafeRef& p) : w_(p.w_) { |
| 54 | // Avoid use-after-move. |
| 55 | CHECK(w_); |
| 56 | } |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 57 | SafeRef& operator=(const SafeRef& p) { |
| 58 | w_ = p.w_; |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame^] | 59 | // Avoid use-after-move. |
| 60 | CHECK(w_); |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 61 | return *this; |
| 62 | } |
| 63 | |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame^] | 64 | // Move construction and assignment. |
| 65 | SafeRef(SafeRef&& p) : w_(std::move(p.w_)) { CHECK(w_); } |
| 66 | SafeRef& operator=(SafeRef&& p) { |
| 67 | w_ = std::move(p.w_); |
| 68 | // Avoid use-after-move. |
| 69 | CHECK(w_); |
| 70 | return *this; |
| 71 | } |
| 72 | |
| 73 | // Copy conversion from SafeRef<U>. |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 74 | template <typename U> |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame^] | 75 | // NOLINTNEXTLINE(google-explicit-constructor) |
| 76 | SafeRef(const SafeRef<U>& p) : w_(p.w_) { |
| 77 | // Avoid use-after-move. |
| 78 | CHECK(w_); |
| 79 | } |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 80 | template <typename U> |
| 81 | SafeRef& operator=(const SafeRef<U>& p) { |
| 82 | w_ = p.w_; |
Daniel Cheng | e31a1bf7 | 2022-07-13 20:18:02 | [diff] [blame^] | 83 | // Avoid use-after-move. |
| 84 | CHECK(w_); |
| 85 | return *this; |
| 86 | } |
| 87 | |
| 88 | // Move conversion from SafeRef<U>. |
| 89 | template <typename U> |
| 90 | // NOLINTNEXTLINE(google-explicit-constructor) |
| 91 | SafeRef(SafeRef<U>&& p) : w_(std::move(p.w_)) { |
| 92 | // Avoid use-after-move. |
| 93 | CHECK(w_); |
| 94 | } |
| 95 | template <typename U> |
| 96 | SafeRef& operator=(SafeRef<U>&& p) { |
| 97 | w_ = std::move(p.w_); |
| 98 | // Avoid use-after-move. |
| 99 | CHECK(w_); |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 100 | return *this; |
| 101 | } |
| 102 | |
| 103 | // Call methods on the underlying T. Will CHECK() if the T pointee is no |
| 104 | // longer alive. |
Eric Orth | 6b0aab5 | 2021-09-30 22:29:34 | [diff] [blame] | 105 | T* operator->() const { |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 106 | // We rely on WeakPtr<T> to CHECK() on a bad deref; tests verify this. |
| 107 | return w_.operator->(); |
| 108 | } |
| 109 | |
| 110 | // Provide access to the underlying T as a reference. Will CHECK() if the T |
| 111 | // pointee is no longer alive. |
Eric Orth | 6b0aab5 | 2021-09-30 22:29:34 | [diff] [blame] | 112 | T& operator*() const { return *operator->(); } |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 113 | |
| 114 | private: |
| 115 | template <typename U> |
| 116 | friend class SafeRef; |
Stephan Hartmann | a951ccf7 | 2021-10-06 18:06:31 | [diff] [blame] | 117 | template <typename U> |
| 118 | friend SafeRef<U> internal::MakeSafeRefFromWeakPtrInternals( |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 119 | const internal::WeakReference& ref, |
Stephan Hartmann | a951ccf7 | 2021-10-06 18:06:31 | [diff] [blame] | 120 | U* ptr); |
danakj | 45c9178 | 2021-09-29 18:23:57 | [diff] [blame] | 121 | |
| 122 | // Construction from a from WeakPtr. Will CHECK() if the WeakPtr is already |
| 123 | // invalid. |
| 124 | explicit SafeRef(WeakPtr<T> w) : w_(std::move(w)) { CHECK(w_); } |
| 125 | |
| 126 | WeakPtr<T> w_; |
| 127 | }; |
| 128 | |
| 129 | namespace internal { |
| 130 | template <typename T> |
| 131 | SafeRef<T> MakeSafeRefFromWeakPtrInternals(const internal::WeakReference& ref, |
| 132 | T* ptr) { |
| 133 | CHECK(ptr); |
| 134 | return SafeRef<T>(WeakPtr<T>(ref, ptr)); |
| 135 | } |
| 136 | } // namespace internal |
| 137 | |
| 138 | } // namespace base |
| 139 | |
| 140 | #endif // BASE_MEMORY_SAFE_REF_H_ |