blob: 479056f06b9712f94aa1a56c1fe399381a667404 [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
Jan Keitel55257c32023-12-14 17:59:528#include <concepts>
9#include <utility>
10
danakj45c91782021-09-29 18:23:5711#include "base/check.h"
Paul Semel5eac04a12023-06-07 18:17:3212#include "base/memory/safe_ref_traits.h"
danakj45c91782021-09-29 18:23:5713#include "base/memory/weak_ptr.h"
14
danakj45c91782021-09-29 18:23:5715namespace base {
16
17// SafeRef smart pointers are used to represent a non-owning pointer to an
18// object, where the pointer is always intended to be valid. These are useful in
19// the same cases that a raw pointer `T*` (or a `T&`) would traditionally be
20// used, as the owner of the SafeRef knows the lifetime of the pointed-to object
21// from other means and will not use the pointer after the pointed-to object is
22// destroyed. However, unlike a `T*` or `T&`, a logic bug will manifest as a
23// benign crash instead of as a Use-after-Free.
24//
Sharon Yang4c7a01d2023-07-28 20:27:3825// SafeRef pointers cannot be null (as expressed by the "Ref" suffix instead of
danakj45c91782021-09-29 18:23:5726// "Ptr"). A SafeRef can be wrapped in an absl::optional if it should not always
27// point to something valid. (A SafePtr sibling type can be introduced if this
28// is problematic, or if consuming moves are needed!)
29//
30// If code wants to track the lifetime of the object directly through its
31// pointer, and dynamically handle the case of the pointer outliving the object
32// it points to, then base::WeakPtr should be used instead.
33//
34// The SafeRef pointer is constructed from a base::WeakPtrFactory's GetSafeRef()
35// method. Since it is tied to the base::WeakPtrFactory, it will consider its
36// pointee invalid when the base::WeakPtrFactory is invalidated, in the same way
37// as base::WeakPtr does, including after a call to InvalidateWeakPtrs().
38//
Sharon Yang4c7a01d2023-07-28 20:27:3839// SafeRefTraits are only meant to mark SafeRefs that were found to be dangling,
Paul Semel5eac04a12023-06-07 18:17:3240// thus one should not use this flag to disable dangling pointer detection on
41// SafeRef. This parameter is set to SafeRefTraits::kEmpty by default.
42//
danakj45c91782021-09-29 18:23:5743// THREAD SAFETY: SafeRef pointers (like base::WeakPtr) may only be used on the
44// sequence (or thread) where the associated base::WeakPtrFactory will be
45// invalidated and/or destroyed. They are safe to passively hold or to destroy
46// on any thread though.
47//
48// This class is expected to one day be replaced by a more flexible and safe
49// smart pointer abstraction which is not tied to base::WeakPtrFactory, such as
50// raw_ptr<T> from the MiraclePtr project (though perhaps a non-nullable raw_ref
51// equivalent).
Paul Semel5eac04a12023-06-07 18:17:3252template <typename T, SafeRefTraits Traits /*= SafeRefTraits::kEmpty*/>
danakj45c91782021-09-29 18:23:5753class SafeRef {
54 public:
55 // No default constructor, since there's no null state. Use an optional
Daniel Chenge31a1bf72022-07-13 20:18:0256 // SafeRef if the pointer may not be present.
danakj45c91782021-09-29 18:23:5757
58 // Copy construction and assignment.
danakjcfcdfb7a2023-02-23 01:05:3559 SafeRef(const SafeRef& other) : ref_(other.ref_), ptr_(other.ptr_) {
Daniel Chenge31a1bf72022-07-13 20:18:0260 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:3561 CHECK(ref_.IsValid());
Daniel Chenge31a1bf72022-07-13 20:18:0262 }
danakjcfcdfb7a2023-02-23 01:05:3563 SafeRef& operator=(const SafeRef& other) {
64 ref_ = other.ref_;
65 ptr_ = other.ptr_;
Daniel Chenge31a1bf72022-07-13 20:18:0266 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:3567 CHECK(ref_.IsValid());
danakj45c91782021-09-29 18:23:5768 return *this;
69 }
70
Daniel Chenge31a1bf72022-07-13 20:18:0271 // Move construction and assignment.
danakjcfcdfb7a2023-02-23 01:05:3572 SafeRef(SafeRef&& other)
73 : ref_(std::move(other.ref_)), ptr_(std::move(other.ptr_)) {
Daniel Chenge31a1bf72022-07-13 20:18:0274 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:3575 CHECK(ref_.IsValid());
76 }
77 SafeRef& operator=(SafeRef&& other) {
78 ref_ = std::move(other.ref_);
79 ptr_ = std::move(other.ptr_);
80 // Avoid use-after-move.
81 CHECK(ref_.IsValid());
Daniel Chenge31a1bf72022-07-13 20:18:0282 return *this;
83 }
84
85 // Copy conversion from SafeRef<U>.
Jan Keitel55257c32023-12-14 17:59:5286 template <typename U>
87 requires(std::convertible_to<U*, T*>)
Daniel Chenge31a1bf72022-07-13 20:18:0288 // NOLINTNEXTLINE(google-explicit-constructor)
danakjcfcdfb7a2023-02-23 01:05:3589 SafeRef(const SafeRef<U>& other)
90 : ref_(other.ref_),
91 ptr_(other.ptr_) // raw_ptr<U> converts to raw_ptr<T>.
92 {
Daniel Chenge31a1bf72022-07-13 20:18:0293 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:3594 CHECK(ref_.IsValid());
Daniel Chenge31a1bf72022-07-13 20:18:0295 }
danakj45c91782021-09-29 18:23:5796 template <typename U>
danakjcfcdfb7a2023-02-23 01:05:3597 SafeRef& operator=(const SafeRef<U>& other) {
98 ref_ = other.ref_;
99 ptr_ = other.ptr_; // raw_ptr<U> converts to raw_ptr<T>.
Daniel Chenge31a1bf72022-07-13 20:18:02100 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:35101 CHECK(ref_.IsValid());
Daniel Chenge31a1bf72022-07-13 20:18:02102 return *this;
103 }
104
105 // Move conversion from SafeRef<U>.
106 template <typename U>
107 // NOLINTNEXTLINE(google-explicit-constructor)
danakjcfcdfb7a2023-02-23 01:05:35108 SafeRef(SafeRef<U>&& other)
109 : ref_(std::move(other.ref_)),
110 ptr_(std::move(other.ptr_)) // raw_ptr<U> converts to raw_ptr<T>.
111 {
Daniel Chenge31a1bf72022-07-13 20:18:02112 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:35113 CHECK(ref_.IsValid());
Daniel Chenge31a1bf72022-07-13 20:18:02114 }
115 template <typename U>
danakjcfcdfb7a2023-02-23 01:05:35116 SafeRef& operator=(SafeRef<U>&& other) {
117 ref_ = std::move(other.ref_);
118 ptr_ = std::move(other.ptr_); // raw_ptr<U> converts to raw_ptr<T>.
Daniel Chenge31a1bf72022-07-13 20:18:02119 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:35120 CHECK(ref_.IsValid());
danakj45c91782021-09-29 18:23:57121 return *this;
122 }
123
danakj45c91782021-09-29 18:23:57124 // Provide access to the underlying T as a reference. Will CHECK() if the T
125 // pointee is no longer alive.
danakjcfcdfb7a2023-02-23 01:05:35126 T& operator*() const {
127 CHECK(ref_.IsValid());
128 return *ptr_;
129 }
130
131 // Used to call methods on the underlying T. Will CHECK() if the T pointee is
132 // no longer alive.
133 T* operator->() const {
134 CHECK(ref_.IsValid());
135 return &*ptr_;
136 }
danakj45c91782021-09-29 18:23:57137
138 private:
Paul Semel5eac04a12023-06-07 18:17:32139 template <typename U, SafeRefTraits PassedTraits>
danakj45c91782021-09-29 18:23:57140 friend class SafeRef;
Stephan Hartmanna951ccf72021-10-06 18:06:31141 template <typename U>
142 friend SafeRef<U> internal::MakeSafeRefFromWeakPtrInternals(
danakjcfcdfb7a2023-02-23 01:05:35143 internal::WeakReference&& ref,
Stephan Hartmanna951ccf72021-10-06 18:06:31144 U* ptr);
danakj45c91782021-09-29 18:23:57145
danakjcfcdfb7a2023-02-23 01:05:35146 // Construction from a from a WeakPtr's internals. Will CHECK() if the WeakPtr
147 // is already invalid.
148 explicit SafeRef(internal::WeakReference&& ref, T* ptr)
149 : ref_(std::move(ref)), ptr_(ptr) {
150 CHECK(ref_.IsValid());
151 }
danakj45c91782021-09-29 18:23:57152
danakjcfcdfb7a2023-02-23 01:05:35153 internal::WeakReference ref_;
154
Paul Semel5eac04a12023-06-07 18:17:32155 static constexpr RawPtrTraits PtrTrait = Traits == SafeRefTraits::kEmpty
156 ? RawPtrTraits::kEmpty
157 : DanglingUntriaged;
danakjcfcdfb7a2023-02-23 01:05:35158 // This pointer is only valid when ref_.is_valid() is true. Otherwise, its
159 // value is undefined (as opposed to nullptr). Unlike WeakPtr, this raw_ptr is
160 // not allowed to dangle.
Paul Semel5eac04a12023-06-07 18:17:32161 raw_ptr<T, PtrTrait> ptr_;
danakj45c91782021-09-29 18:23:57162};
163
164namespace internal {
165template <typename T>
danakjcfcdfb7a2023-02-23 01:05:35166SafeRef<T> MakeSafeRefFromWeakPtrInternals(internal::WeakReference&& ref,
danakj45c91782021-09-29 18:23:57167 T* ptr) {
danakjcfcdfb7a2023-02-23 01:05:35168 return SafeRef<T>(std::move(ref), ptr);
danakj45c91782021-09-29 18:23:57169}
170} // namespace internal
171
172} // namespace base
173
174#endif // BASE_MEMORY_SAFE_REF_H_