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