blob: e7280ab5668f5e0f96d5ed0fa0ed184e199be993 [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
8#include "base/check.h"
Paul Semel5eac04a12023-06-07 18:17:329#include "base/memory/safe_ref_traits.h"
danakj45c91782021-09-29 18:23:5710#include "base/memory/weak_ptr.h"
11
12#include <utility>
13
14namespace 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 can not 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//
Paul Semel5eac04a12023-06-07 18:17:3238// SafeRefTraits are only meant to mark SafeRef 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//
danakj45c91782021-09-29 18:23:5742// 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).
Paul Semel5eac04a12023-06-07 18:17:3251template <typename T, SafeRefTraits Traits /*= SafeRefTraits::kEmpty*/>
danakj45c91782021-09-29 18:23:5752class SafeRef {
53 public:
54 // No default constructor, since there's no null state. Use an optional
Daniel Chenge31a1bf72022-07-13 20:18:0255 // SafeRef if the pointer may not be present.
danakj45c91782021-09-29 18:23:5756
57 // Copy construction and assignment.
danakjcfcdfb7a2023-02-23 01:05:3558 SafeRef(const SafeRef& other) : ref_(other.ref_), ptr_(other.ptr_) {
Daniel Chenge31a1bf72022-07-13 20:18:0259 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:3560 CHECK(ref_.IsValid());
Daniel Chenge31a1bf72022-07-13 20:18:0261 }
danakjcfcdfb7a2023-02-23 01:05:3562 SafeRef& operator=(const SafeRef& other) {
63 ref_ = other.ref_;
64 ptr_ = other.ptr_;
Daniel Chenge31a1bf72022-07-13 20:18:0265 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:3566 CHECK(ref_.IsValid());
danakj45c91782021-09-29 18:23:5767 return *this;
68 }
69
Daniel Chenge31a1bf72022-07-13 20:18:0270 // Move construction and assignment.
danakjcfcdfb7a2023-02-23 01:05:3571 SafeRef(SafeRef&& other)
72 : ref_(std::move(other.ref_)), ptr_(std::move(other.ptr_)) {
Daniel Chenge31a1bf72022-07-13 20:18:0273 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:3574 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());
Daniel Chenge31a1bf72022-07-13 20:18:0281 return *this;
82 }
83
84 // Copy conversion from SafeRef<U>.
danakjcfcdfb7a2023-02-23 01:05:3585 template <typename U,
86 typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
Daniel Chenge31a1bf72022-07-13 20:18:0287 // NOLINTNEXTLINE(google-explicit-constructor)
danakjcfcdfb7a2023-02-23 01:05:3588 SafeRef(const SafeRef<U>& other)
89 : ref_(other.ref_),
90 ptr_(other.ptr_) // raw_ptr<U> converts to raw_ptr<T>.
91 {
Daniel Chenge31a1bf72022-07-13 20:18:0292 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:3593 CHECK(ref_.IsValid());
Daniel Chenge31a1bf72022-07-13 20:18:0294 }
danakj45c91782021-09-29 18:23:5795 template <typename U>
danakjcfcdfb7a2023-02-23 01:05:3596 SafeRef& operator=(const SafeRef<U>& other) {
97 ref_ = other.ref_;
98 ptr_ = other.ptr_; // raw_ptr<U> converts to raw_ptr<T>.
Daniel Chenge31a1bf72022-07-13 20:18:0299 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:35100 CHECK(ref_.IsValid());
Daniel Chenge31a1bf72022-07-13 20:18:02101 return *this;
102 }
103
104 // Move conversion from SafeRef<U>.
105 template <typename U>
106 // NOLINTNEXTLINE(google-explicit-constructor)
danakjcfcdfb7a2023-02-23 01:05:35107 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 {
Daniel Chenge31a1bf72022-07-13 20:18:02111 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:35112 CHECK(ref_.IsValid());
Daniel Chenge31a1bf72022-07-13 20:18:02113 }
114 template <typename U>
danakjcfcdfb7a2023-02-23 01:05:35115 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>.
Daniel Chenge31a1bf72022-07-13 20:18:02118 // Avoid use-after-move.
danakjcfcdfb7a2023-02-23 01:05:35119 CHECK(ref_.IsValid());
danakj45c91782021-09-29 18:23:57120 return *this;
121 }
122
danakj45c91782021-09-29 18:23:57123 // Provide access to the underlying T as a reference. Will CHECK() if the T
124 // pointee is no longer alive.
danakjcfcdfb7a2023-02-23 01:05:35125 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 }
danakj45c91782021-09-29 18:23:57136
137 private:
Paul Semel5eac04a12023-06-07 18:17:32138 template <typename U, SafeRefTraits PassedTraits>
danakj45c91782021-09-29 18:23:57139 friend class SafeRef;
Stephan Hartmanna951ccf72021-10-06 18:06:31140 template <typename U>
141 friend SafeRef<U> internal::MakeSafeRefFromWeakPtrInternals(
danakjcfcdfb7a2023-02-23 01:05:35142 internal::WeakReference&& ref,
Stephan Hartmanna951ccf72021-10-06 18:06:31143 U* ptr);
danakj45c91782021-09-29 18:23:57144
danakjcfcdfb7a2023-02-23 01:05:35145 // Construction from a from a WeakPtr's internals. Will CHECK() if the WeakPtr
146 // is already invalid.
147 explicit SafeRef(internal::WeakReference&& ref, T* ptr)
148 : ref_(std::move(ref)), ptr_(ptr) {
149 CHECK(ref_.IsValid());
150 }
danakj45c91782021-09-29 18:23:57151
danakjcfcdfb7a2023-02-23 01:05:35152 internal::WeakReference ref_;
153
Paul Semel5eac04a12023-06-07 18:17:32154 static constexpr RawPtrTraits PtrTrait = Traits == SafeRefTraits::kEmpty
155 ? RawPtrTraits::kEmpty
156 : DanglingUntriaged;
danakjcfcdfb7a2023-02-23 01:05:35157 // 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.
Paul Semel5eac04a12023-06-07 18:17:32160 raw_ptr<T, PtrTrait> ptr_;
danakj45c91782021-09-29 18:23:57161};
162
163namespace internal {
164template <typename T>
danakjcfcdfb7a2023-02-23 01:05:35165SafeRef<T> MakeSafeRefFromWeakPtrInternals(internal::WeakReference&& ref,
danakj45c91782021-09-29 18:23:57166 T* ptr) {
danakjcfcdfb7a2023-02-23 01:05:35167 return SafeRef<T>(std::move(ref), ptr);
danakj45c91782021-09-29 18:23:57168}
169} // namespace internal
170
171} // namespace base
172
173#endif // BASE_MEMORY_SAFE_REF_H_