• 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/safe_ref_traits.h"
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 cannot 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 //
38 // SafeRefTraits are only meant to mark SafeRefs 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 //
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).
51 template <typename T, SafeRefTraits Traits /*= SafeRefTraits::kEmpty*/>
52 class SafeRef {
53  public:
54   // No default constructor, since there's no null state. Use an optional
55   // SafeRef if the pointer may not be present.
56 
57   // Copy construction and assignment.
SafeRef(const SafeRef & other)58   SafeRef(const SafeRef& other) : ref_(other.ref_), ptr_(other.ptr_) {
59     // Avoid use-after-move.
60     CHECK(ref_.IsValid());
61   }
62   SafeRef& operator=(const SafeRef& other) {
63     ref_ = other.ref_;
64     ptr_ = other.ptr_;
65     // Avoid use-after-move.
66     CHECK(ref_.IsValid());
67     return *this;
68   }
69 
70   // Move construction and assignment.
SafeRef(SafeRef && other)71   SafeRef(SafeRef&& other)
72       : ref_(std::move(other.ref_)), ptr_(std::move(other.ptr_)) {
73     // Avoid use-after-move.
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());
81     return *this;
82   }
83 
84   // Copy conversion from SafeRef<U>.
85   template <typename U,
86             typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
87   // NOLINTNEXTLINE(google-explicit-constructor)
SafeRef(const SafeRef<U> & other)88   SafeRef(const SafeRef<U>& other)
89       : ref_(other.ref_),
90         ptr_(other.ptr_)  // raw_ptr<U> converts to raw_ptr<T>.
91   {
92     // Avoid use-after-move.
93     CHECK(ref_.IsValid());
94   }
95   template <typename U>
96   SafeRef& operator=(const SafeRef<U>& other) {
97     ref_ = other.ref_;
98     ptr_ = other.ptr_;  // raw_ptr<U> converts to raw_ptr<T>.
99     // Avoid use-after-move.
100     CHECK(ref_.IsValid());
101     return *this;
102   }
103 
104   // Move conversion from SafeRef<U>.
105   template <typename U>
106   // NOLINTNEXTLINE(google-explicit-constructor)
SafeRef(SafeRef<U> && other)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   {
111     // Avoid use-after-move.
112     CHECK(ref_.IsValid());
113   }
114   template <typename U>
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>.
118     // Avoid use-after-move.
119     CHECK(ref_.IsValid());
120     return *this;
121   }
122 
123   // Provide access to the underlying T as a reference. Will CHECK() if the T
124   // pointee is no longer alive.
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   }
136 
137  private:
138   template <typename U, SafeRefTraits PassedTraits>
139   friend class SafeRef;
140   template <typename U>
141   friend SafeRef<U> internal::MakeSafeRefFromWeakPtrInternals(
142       internal::WeakReference&& ref,
143       U* ptr);
144 
145   // Construction from a from a WeakPtr's internals. Will CHECK() if the WeakPtr
146   // is already invalid.
SafeRef(internal::WeakReference && ref,T * ptr)147   explicit SafeRef(internal::WeakReference&& ref, T* ptr)
148       : ref_(std::move(ref)), ptr_(ptr) {
149     CHECK(ref_.IsValid());
150   }
151 
152   internal::WeakReference ref_;
153 
154   static constexpr RawPtrTraits PtrTrait = Traits == SafeRefTraits::kEmpty
155                                                ? RawPtrTraits::kEmpty
156                                                : DanglingUntriaged;
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.
160   raw_ptr<T, PtrTrait> ptr_;
161 };
162 
163 namespace internal {
164 template <typename T>
MakeSafeRefFromWeakPtrInternals(internal::WeakReference && ref,T * ptr)165 SafeRef<T> MakeSafeRefFromWeakPtrInternals(internal::WeakReference&& ref,
166                                            T* ptr) {
167   return SafeRef<T>(std::move(ref), ptr);
168 }
169 }  // namespace internal
170 
171 }  // namespace base
172 
173 #endif  // BASE_MEMORY_SAFE_REF_H_
174