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
|
// 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 "base/check.h"
#include "base/memory/safe_ref_traits.h"
#include "base/memory/weak_ptr.h"
#include <utility>
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 absl::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,
typename = std::enable_if_t<std::is_convertible_v<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;
}
// 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_
|