• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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_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
50   // SafeRef if the pointer may not be present.
51 
52   // Copy construction and assignment.
SafeRef(const SafeRef & other)53   SafeRef(const SafeRef& other) : ref_(other.ref_), ptr_(other.ptr_) {
54     // Avoid use-after-move.
55     CHECK(ref_.IsValid());
56   }
57   SafeRef& operator=(const SafeRef& other) {
58     ref_ = other.ref_;
59     ptr_ = other.ptr_;
60     // Avoid use-after-move.
61     CHECK(ref_.IsValid());
62     return *this;
63   }
64 
65   // Move construction and assignment.
SafeRef(SafeRef && other)66   SafeRef(SafeRef&& other)
67       : ref_(std::move(other.ref_)), ptr_(std::move(other.ptr_)) {
68     // Avoid use-after-move.
69     CHECK(ref_.IsValid());
70   }
71   SafeRef& operator=(SafeRef&& other) {
72     ref_ = std::move(other.ref_);
73     ptr_ = std::move(other.ptr_);
74     // Avoid use-after-move.
75     CHECK(ref_.IsValid());
76     return *this;
77   }
78 
79   // Copy conversion from SafeRef<U>.
80   template <typename U,
81             typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
82   // NOLINTNEXTLINE(google-explicit-constructor)
SafeRef(const SafeRef<U> & other)83   SafeRef(const SafeRef<U>& other)
84       : ref_(other.ref_),
85         ptr_(other.ptr_)  // raw_ptr<U> converts to raw_ptr<T>.
86   {
87     // Avoid use-after-move.
88     CHECK(ref_.IsValid());
89   }
90   template <typename U>
91   SafeRef& operator=(const SafeRef<U>& other) {
92     ref_ = other.ref_;
93     ptr_ = other.ptr_;  // raw_ptr<U> converts to raw_ptr<T>.
94     // Avoid use-after-move.
95     CHECK(ref_.IsValid());
96     return *this;
97   }
98 
99   // Move conversion from SafeRef<U>.
100   template <typename U>
101   // NOLINTNEXTLINE(google-explicit-constructor)
SafeRef(SafeRef<U> && other)102   SafeRef(SafeRef<U>&& other)
103       : ref_(std::move(other.ref_)),
104         ptr_(std::move(other.ptr_))  // raw_ptr<U> converts to raw_ptr<T>.
105   {
106     // Avoid use-after-move.
107     CHECK(ref_.IsValid());
108   }
109   template <typename U>
110   SafeRef& operator=(SafeRef<U>&& other) {
111     ref_ = std::move(other.ref_);
112     ptr_ = std::move(other.ptr_);  // raw_ptr<U> converts to raw_ptr<T>.
113     // Avoid use-after-move.
114     CHECK(ref_.IsValid());
115     return *this;
116   }
117 
118   // Provide access to the underlying T as a reference. Will CHECK() if the T
119   // pointee is no longer alive.
120   T& operator*() const {
121     CHECK(ref_.IsValid());
122     return *ptr_;
123   }
124 
125   // Used to call methods on the underlying T. Will CHECK() if the T pointee is
126   // no longer alive.
127   T* operator->() const {
128     CHECK(ref_.IsValid());
129     return &*ptr_;
130   }
131 
132  private:
133   template <typename U>
134   friend class SafeRef;
135   template <typename U>
136   friend SafeRef<U> internal::MakeSafeRefFromWeakPtrInternals(
137       internal::WeakReference&& ref,
138       U* ptr);
139 
140   // Construction from a from a WeakPtr's internals. Will CHECK() if the WeakPtr
141   // is already invalid.
SafeRef(internal::WeakReference && ref,T * ptr)142   explicit SafeRef(internal::WeakReference&& ref, T* ptr)
143       : ref_(std::move(ref)), ptr_(ptr) {
144     CHECK(ref_.IsValid());
145   }
146 
147   internal::WeakReference ref_;
148 
149   // This pointer is only valid when ref_.is_valid() is true.  Otherwise, its
150   // value is undefined (as opposed to nullptr). Unlike WeakPtr, this raw_ptr is
151   // not allowed to dangle.
152   raw_ptr<T> ptr_;
153 };
154 
155 namespace internal {
156 template <typename T>
MakeSafeRefFromWeakPtrInternals(internal::WeakReference && ref,T * ptr)157 SafeRef<T> MakeSafeRefFromWeakPtrInternals(internal::WeakReference&& ref,
158                                            T* ptr) {
159   return SafeRef<T>(std::move(ref), ptr);
160 }
161 }  // namespace internal
162 
163 }  // namespace base
164 
165 #endif  // BASE_MEMORY_SAFE_REF_H_
166