blob: 08c95198e9e1b847d98a6cb9d1ed56e99df75328 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2021 The Chromium Authors
danakj45c91782021-09-29 18:23:572// 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
Kenichi Ishibashidcb0ece2024-03-21 04:03:308#include <compare>
Jan Keitel55257c32023-12-14 17:59:529#include <concepts>
10#include <utility>
11
danakj45c91782021-09-29 18:23:5712#include "base/check.h"
Paul Semel5eac04a12023-06-07 18:17:3213#include "base/memory/safe_ref_traits.h"
danakj45c91782021-09-29 18:23:5714#include "base/memory/weak_ptr.h"
15
danakj45c91782021-09-29 18:23:5716namespace base {
17
18// SafeRef smart pointers are used to represent a non-owning pointer to an
19// object, where the pointer is always intended to be valid. These are useful in
20// the same cases that a raw pointer `T*` (or a `T&`) would traditionally be
21// used, as the owner of the SafeRef knows the lifetime of the pointed-to object
22// from other means and will not use the pointer after the pointed-to object is
23// destroyed. However, unlike a `T*` or `T&`, a logic bug will manifest as a
24// benign crash instead of as a Use-after-Free.
25//
Sharon Yang4c7a01d2023-07-28 20:27:3826// SafeRef pointers cannot be null (as expressed by the "Ref" suffix instead of
Arthur Sonzognie5fff99c2024-02-21 15:58:2427// "Ptr"). A SafeRef can be wrapped in an std::optional if it should not always
danakj45c91782021-09-29 18:23:5728// point to something valid. (A SafePtr sibling type can be introduced if this
29// is problematic, or if consuming moves are needed!)
30//
31// If code wants to track the lifetime of the object directly through its
32// pointer, and dynamically handle the case of the pointer outliving the object
33// it points to, then base::WeakPtr should be used instead.
34//
35// The SafeRef pointer is constructed from a base::WeakPtrFactory's GetSafeRef()
36// method. Since it is tied to the base::WeakPtrFactory, it will consider its
37// pointee invalid when the base::WeakPtrFactory is invalidated, in the same way
38// as base::WeakPtr does, including after a call to InvalidateWeakPtrs().
39//
Sharon Yang4c7a01d2023-07-28 20:27:3840// SafeRefTraits are only meant to mark SafeRefs that were found to be dangling,
Paul Semel5eac04a12023-06-07 18:17:3241// thus one should not use this flag to disable dangling pointer detection on
42// SafeRef. This parameter is set to SafeRefTraits::kEmpty by default.
43//
danakj45c91782021-09-29 18:23:5744// THREAD SAFETY: SafeRef pointers (like base::WeakPtr) may only be used on the
45// sequence (or thread) where the associated base::WeakPtrFactory will be
46// invalidated and/or destroyed. They are safe to passively hold or to destroy
47// on any thread though.
48//
49// This class is expected to one day be replaced by a more flexible and safe
50// smart pointer abstraction which is not tied to base::WeakPtrFactory, such as
51// raw_ptr<T> from the MiraclePtr project (though perhaps a non-nullable raw_ref
52// equivalent).
Paul Semel5eac04a12023-06-07 18:17:3253template <typename T, SafeRefTraits Traits /*= SafeRefTraits::kEmpty*/>
danakj45c91782021-09-29 18:23:5754class SafeRef {
55 public:
56 // No default constructor, since there's no null state. Use an optional
Daniel Chenge31a1bf72022-07-13 20:18:0257 // SafeRef if the pointer may not be present.
danakj45c91782021-09-29 18:23:5758
59 // Copy construction and assignment.
danakjcfcdfb7a2023-02-23 01:05:3560 SafeRef(const SafeRef& other) : ref_(other.ref_), ptr_(other.ptr_) {
Daniel Chenge31a1bf72022-07-13 20:18:0261 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:3562 CHECK(ref_.IsValid());
Daniel Chenge31a1bf72022-07-13 20:18:0263 }
danakjcfcdfb7a2023-02-23 01:05:3564 SafeRef& operator=(const SafeRef& other) {
65 ref_ = other.ref_;
66 ptr_ = other.ptr_;
Daniel Chenge31a1bf72022-07-13 20:18:0267 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:3568 CHECK(ref_.IsValid());
danakj45c91782021-09-29 18:23:5769 return *this;
70 }
71
Daniel Chenge31a1bf72022-07-13 20:18:0272 // Move construction and assignment.
danakjcfcdfb7a2023-02-23 01:05:3573 SafeRef(SafeRef&& other)
74 : ref_(std::move(other.ref_)), ptr_(std::move(other.ptr_)) {
Daniel Chenge31a1bf72022-07-13 20:18:0275 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:3576 CHECK(ref_.IsValid());
77 }
78 SafeRef& operator=(SafeRef&& other) {
79 ref_ = std::move(other.ref_);
80 ptr_ = std::move(other.ptr_);
81 // Avoid use-after-move.
82 CHECK(ref_.IsValid());
Daniel Chenge31a1bf72022-07-13 20:18:0283 return *this;
84 }
85
86 // Copy conversion from SafeRef<U>.
Jan Keitel55257c32023-12-14 17:59:5287 template <typename U>
88 requires(std::convertible_to<U*, T*>)
Daniel Chenge31a1bf72022-07-13 20:18:0289 // NOLINTNEXTLINE(google-explicit-constructor)
danakjcfcdfb7a2023-02-23 01:05:3590 SafeRef(const SafeRef<U>& other)
91 : ref_(other.ref_),
92 ptr_(other.ptr_) // raw_ptr<U> converts to raw_ptr<T>.
93 {
Daniel Chenge31a1bf72022-07-13 20:18:0294 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:3595 CHECK(ref_.IsValid());
Daniel Chenge31a1bf72022-07-13 20:18:0296 }
danakj45c91782021-09-29 18:23:5797 template <typename U>
danakjcfcdfb7a2023-02-23 01:05:3598 SafeRef& operator=(const SafeRef<U>& other) {
99 ref_ = other.ref_;
100 ptr_ = other.ptr_; // raw_ptr<U> converts to raw_ptr<T>.
Daniel Chenge31a1bf72022-07-13 20:18:02101 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:35102 CHECK(ref_.IsValid());
Daniel Chenge31a1bf72022-07-13 20:18:02103 return *this;
104 }
105
106 // Move conversion from SafeRef<U>.
107 template <typename U>
108 // NOLINTNEXTLINE(google-explicit-constructor)
danakjcfcdfb7a2023-02-23 01:05:35109 SafeRef(SafeRef<U>&& other)
110 : ref_(std::move(other.ref_)),
111 ptr_(std::move(other.ptr_)) // raw_ptr<U> converts to raw_ptr<T>.
112 {
Daniel Chenge31a1bf72022-07-13 20:18:02113 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:35114 CHECK(ref_.IsValid());
Daniel Chenge31a1bf72022-07-13 20:18:02115 }
116 template <typename U>
danakjcfcdfb7a2023-02-23 01:05:35117 SafeRef& operator=(SafeRef<U>&& other) {
118 ref_ = std::move(other.ref_);
119 ptr_ = std::move(other.ptr_); // raw_ptr<U> converts to raw_ptr<T>.
Daniel Chenge31a1bf72022-07-13 20:18:02120 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:35121 CHECK(ref_.IsValid());
danakj45c91782021-09-29 18:23:57122 return *this;
123 }
124
Kenichi Ishibashidcb0ece2024-03-21 04:03:30125 // Ordered by the pointer, not the pointee.
126 template <typename U>
127 std::strong_ordering operator<=>(const SafeRef<U>& other) const {
128 return ptr_ <=> other.ptr_;
129 }
130
danakj45c91782021-09-29 18:23:57131 // Provide access to the underlying T as a reference. Will CHECK() if the T
132 // pointee is no longer alive.
danakjcfcdfb7a2023-02-23 01:05:35133 T& operator*() const {
134 CHECK(ref_.IsValid());
135 return *ptr_;
136 }
137
138 // Used to call methods on the underlying T. Will CHECK() if the T pointee is
139 // no longer alive.
140 T* operator->() const {
141 CHECK(ref_.IsValid());
142 return &*ptr_;
143 }
danakj45c91782021-09-29 18:23:57144
145 private:
Paul Semel5eac04a12023-06-07 18:17:32146 template <typename U, SafeRefTraits PassedTraits>
danakj45c91782021-09-29 18:23:57147 friend class SafeRef;
Stephan Hartmanna951ccf72021-10-06 18:06:31148 template <typename U>
149 friend SafeRef<U> internal::MakeSafeRefFromWeakPtrInternals(
danakjcfcdfb7a2023-02-23 01:05:35150 internal::WeakReference&& ref,
Stephan Hartmanna951ccf72021-10-06 18:06:31151 U* ptr);
danakj45c91782021-09-29 18:23:57152
danakjcfcdfb7a2023-02-23 01:05:35153 // Construction from a from a WeakPtr's internals. Will CHECK() if the WeakPtr
154 // is already invalid.
Lei Zhangb39481fd2025-06-26 01:03:40155 SafeRef(internal::WeakReference&& ref, T* ptr)
danakjcfcdfb7a2023-02-23 01:05:35156 : ref_(std::move(ref)), ptr_(ptr) {
157 CHECK(ref_.IsValid());
158 }
danakj45c91782021-09-29 18:23:57159
danakjcfcdfb7a2023-02-23 01:05:35160 internal::WeakReference ref_;
161
Paul Semel5eac04a12023-06-07 18:17:32162 static constexpr RawPtrTraits PtrTrait = Traits == SafeRefTraits::kEmpty
163 ? RawPtrTraits::kEmpty
164 : DanglingUntriaged;
danakjcfcdfb7a2023-02-23 01:05:35165 // This pointer is only valid when ref_.is_valid() is true. Otherwise, its
166 // value is undefined (as opposed to nullptr). Unlike WeakPtr, this raw_ptr is
167 // not allowed to dangle.
Paul Semel5eac04a12023-06-07 18:17:32168 raw_ptr<T, PtrTrait> ptr_;
danakj45c91782021-09-29 18:23:57169};
170
171namespace internal {
172template <typename T>
danakjcfcdfb7a2023-02-23 01:05:35173SafeRef<T> MakeSafeRefFromWeakPtrInternals(internal::WeakReference&& ref,
danakj45c91782021-09-29 18:23:57174 T* ptr) {
danakjcfcdfb7a2023-02-23 01:05:35175 return SafeRef<T>(std::move(ref), ptr);
danakj45c91782021-09-29 18:23:57176}
177} // namespace internal
178
179} // namespace base
180
181#endif // BASE_MEMORY_SAFE_REF_H_