xref: /aosp_15_r20/external/cronet/base/memory/scoped_refptr.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2017 The Chromium Authors
2 // 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_SCOPED_REFPTR_H_
6 #define BASE_MEMORY_SCOPED_REFPTR_H_
7 
8 #include <stddef.h>
9 
10 #include <compare>
11 #include <concepts>
12 #include <iosfwd>
13 #include <type_traits>
14 #include <utility>
15 
16 #include "base/check.h"
17 #include "base/compiler_specific.h"
18 #include "base/memory/raw_ptr_exclusion.h"
19 
20 template <class T>
21 class scoped_refptr;
22 
23 namespace base {
24 
25 template <class, typename>
26 class RefCounted;
27 template <class, typename>
28 class RefCountedThreadSafe;
29 template <class>
30 class RefCountedDeleteOnSequence;
31 class SequencedTaskRunner;
32 
33 template <typename T>
34 scoped_refptr<T> AdoptRef(T* t);
35 
36 namespace subtle {
37 
38 enum AdoptRefTag { kAdoptRefTag };
39 enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag };
40 enum StartRefCountFromOneTag { kStartRefCountFromOneTag };
41 
42 template <typename TagType>
43 struct RefCountPreferenceTagTraits;
44 
45 template <>
46 struct RefCountPreferenceTagTraits<StartRefCountFromZeroTag> {
47   static constexpr StartRefCountFromZeroTag kTag = kStartRefCountFromZeroTag;
48 };
49 
50 template <>
51 struct RefCountPreferenceTagTraits<StartRefCountFromOneTag> {
52   static constexpr StartRefCountFromOneTag kTag = kStartRefCountFromOneTag;
53 };
54 
55 template <typename T, typename Tag = typename T::RefCountPreferenceTag>
56 constexpr Tag GetRefCountPreference() {
57   return RefCountPreferenceTagTraits<Tag>::kTag;
58 }
59 
60 // scoped_refptr<T> is typically used with one of several RefCounted<T> base
61 // classes or with custom AddRef and Release methods. These overloads dispatch
62 // on which was used.
63 
64 template <typename T, typename U, typename V>
65 constexpr bool IsRefCountPreferenceOverridden(const T*,
66                                               const RefCounted<U, V>*) {
67   return !std::same_as<std::decay_t<decltype(GetRefCountPreference<T>())>,
68                        std::decay_t<decltype(GetRefCountPreference<U>())>>;
69 }
70 
71 template <typename T, typename U, typename V>
72 constexpr bool IsRefCountPreferenceOverridden(
73     const T*,
74     const RefCountedThreadSafe<U, V>*) {
75   return !std::same_as<std::decay_t<decltype(GetRefCountPreference<T>())>,
76                        std::decay_t<decltype(GetRefCountPreference<U>())>>;
77 }
78 
79 template <typename T, typename U>
80 constexpr bool IsRefCountPreferenceOverridden(
81     const T*,
82     const RefCountedDeleteOnSequence<U>*) {
83   return !std::same_as<std::decay_t<decltype(GetRefCountPreference<T>())>,
84                        std::decay_t<decltype(GetRefCountPreference<U>())>>;
85 }
86 
87 constexpr bool IsRefCountPreferenceOverridden(...) {
88   return false;
89 }
90 
91 template <typename T, typename U, typename V>
92 constexpr void AssertRefCountBaseMatches(const T*, const RefCounted<U, V>*) {
93   static_assert(std::derived_from<T, U>,
94                 "T implements RefCounted<U>, but U is not a base of T.");
95 }
96 
97 template <typename T, typename U, typename V>
98 constexpr void AssertRefCountBaseMatches(const T*,
99                                          const RefCountedThreadSafe<U, V>*) {
100   static_assert(
101       std::derived_from<T, U>,
102       "T implements RefCountedThreadSafe<U>, but U is not a base of T.");
103 }
104 
105 template <typename T, typename U>
106 constexpr void AssertRefCountBaseMatches(const T*,
107                                          const RefCountedDeleteOnSequence<U>*) {
108   static_assert(
109       std::derived_from<T, U>,
110       "T implements RefCountedDeleteOnSequence<U>, but U is not a base of T.");
111 }
112 
113 constexpr void AssertRefCountBaseMatches(...) {}
114 
115 }  // namespace subtle
116 
117 // Creates a scoped_refptr from a raw pointer without incrementing the reference
118 // count. Use this only for a newly created object whose reference count starts
119 // from 1 instead of 0.
120 template <typename T>
121 scoped_refptr<T> AdoptRef(T* obj) {
122   using Tag = std::decay_t<decltype(subtle::GetRefCountPreference<T>())>;
123   static_assert(std::same_as<subtle::StartRefCountFromOneTag, Tag>,
124                 "Use AdoptRef only if the reference count starts from one.");
125 
126   DCHECK(obj);
127   DCHECK(obj->HasOneRef());
128   obj->Adopted();
129   return scoped_refptr<T>(obj, subtle::kAdoptRefTag);
130 }
131 
132 namespace subtle {
133 
134 template <typename T>
135 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) {
136   return scoped_refptr<T>(obj);
137 }
138 
139 template <typename T>
140 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) {
141   return AdoptRef(obj);
142 }
143 
144 }  // namespace subtle
145 
146 // Constructs an instance of T, which is a ref counted type, and wraps the
147 // object into a scoped_refptr<T>.
148 template <typename T, typename... Args>
149 scoped_refptr<T> MakeRefCounted(Args&&... args) {
150   T* obj = new T(std::forward<Args>(args)...);
151   return subtle::AdoptRefIfNeeded(obj, subtle::GetRefCountPreference<T>());
152 }
153 
154 // Takes an instance of T, which is a ref counted type, and wraps the object
155 // into a scoped_refptr<T>.
156 template <typename T>
157 scoped_refptr<T> WrapRefCounted(T* t) {
158   return scoped_refptr<T>(t);
159 }
160 
161 }  // namespace base
162 
163 //
164 // A smart pointer class for reference counted objects.  Use this class instead
165 // of calling AddRef and Release manually on a reference counted object to
166 // avoid common memory leaks caused by forgetting to Release an object
167 // reference.  Sample usage:
168 //
169 //   class MyFoo : public RefCounted<MyFoo> {
170 //    ...
171 //    private:
172 //     friend class RefCounted<MyFoo>;  // Allow destruction by RefCounted<>.
173 //     ~MyFoo();                        // Destructor must be private/protected.
174 //   };
175 //
176 //   void some_function() {
177 //     scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
178 //     foo->Method(param);
179 //     // |foo| is released when this function returns
180 //   }
181 //
182 //   void some_other_function() {
183 //     scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
184 //     ...
185 //     foo.reset();  // explicitly releases |foo|
186 //     ...
187 //     if (foo)
188 //       foo->Method(param);
189 //   }
190 //
191 // The above examples show how scoped_refptr<T> acts like a pointer to T.
192 // Given two scoped_refptr<T> classes, it is also possible to exchange
193 // references between the two objects, like so:
194 //
195 //   {
196 //     scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
197 //     scoped_refptr<MyFoo> b;
198 //
199 //     b.swap(a);
200 //     // now, |b| references the MyFoo object, and |a| references nullptr.
201 //   }
202 //
203 // To make both |a| and |b| in the above example reference the same MyFoo
204 // object, simply use the assignment operator:
205 //
206 //   {
207 //     scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
208 //     scoped_refptr<MyFoo> b;
209 //
210 //     b = a;
211 //     // now, |a| and |b| each own a reference to the same MyFoo object.
212 //   }
213 //
214 // Also see Chromium's ownership and calling conventions:
215 // https://chromium.googlesource.com/chromium/src/+/lkgr/styleguide/c++/c++.md#object-ownership-and-calling-conventions
216 // Specifically:
217 //   If the function (at least sometimes) takes a ref on a refcounted object,
218 //   declare the param as scoped_refptr<T>. The caller can decide whether it
219 //   wishes to transfer ownership (by calling std::move(t) when passing t) or
220 //   retain its ref (by simply passing t directly).
221 //   In other words, use scoped_refptr like you would a std::unique_ptr except
222 //   in the odd case where it's required to hold on to a ref while handing one
223 //   to another component (if a component merely needs to use t on the stack
224 //   without keeping a ref: pass t as a raw T*).
225 template <class T>
226 class TRIVIAL_ABI scoped_refptr {
227  public:
228   typedef T element_type;
229 
230   constexpr scoped_refptr() = default;
231 
232   // Allow implicit construction from nullptr.
233   constexpr scoped_refptr(std::nullptr_t) {}
234 
235   // Constructs from a raw pointer. Note that this constructor allows implicit
236   // conversion from T* to scoped_refptr<T> which is strongly discouraged. If
237   // you are creating a new ref-counted object please use
238   // base::MakeRefCounted<T>() or base::WrapRefCounted<T>(). Otherwise you
239   // should move or copy construct from an existing scoped_refptr<T> to the
240   // ref-counted object.
241   scoped_refptr(T* p) : ptr_(p) {
242     if (ptr_)
243       AddRef(ptr_);
244   }
245 
246   // Copy constructor. This is required in addition to the copy conversion
247   // constructor below.
248   scoped_refptr(const scoped_refptr& r) : scoped_refptr(r.ptr_) {}
249 
250   // Copy conversion constructor.
251   template <typename U>
252     requires(std::convertible_to<U*, T*>)
253   scoped_refptr(const scoped_refptr<U>& r) : scoped_refptr(r.ptr_) {}
254 
255   // Move constructor. This is required in addition to the move conversion
256   // constructor below.
257   scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.ptr_) { r.ptr_ = nullptr; }
258 
259   // Move conversion constructor.
260   template <typename U>
261     requires(std::convertible_to<U*, T*>)
262   scoped_refptr(scoped_refptr<U>&& r) noexcept : ptr_(r.ptr_) {
263     r.ptr_ = nullptr;
264   }
265 
266   ~scoped_refptr() {
267     static_assert(!base::subtle::IsRefCountPreferenceOverridden(
268                       static_cast<T*>(nullptr), static_cast<T*>(nullptr)),
269                   "It's unsafe to override the ref count preference."
270                   " Please remove REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE"
271                   " from subclasses.");
272     if (ptr_)
273       Release(ptr_);
274   }
275 
276   T* get() const { return ptr_; }
277 
278   T& operator*() const {
279     DCHECK(ptr_);
280     return *ptr_;
281   }
282 
283   T* operator->() const {
284     DCHECK(ptr_);
285     return ptr_;
286   }
287 
288   scoped_refptr& operator=(std::nullptr_t) {
289     reset();
290     return *this;
291   }
292 
293   scoped_refptr& operator=(T* p) { return *this = scoped_refptr(p); }
294 
295   // Unified assignment operator.
296   scoped_refptr& operator=(scoped_refptr r) noexcept {
297     swap(r);
298     return *this;
299   }
300 
301   // Sets managed object to null and releases reference to the previous managed
302   // object, if it existed.
303   void reset() { scoped_refptr().swap(*this); }
304 
305   // Returns the owned pointer (if any), releasing ownership to the caller. The
306   // caller is responsible for managing the lifetime of the reference.
307   [[nodiscard]] T* release();
308 
309   void swap(scoped_refptr& r) noexcept { std::swap(ptr_, r.ptr_); }
310 
311   explicit operator bool() const { return ptr_ != nullptr; }
312 
313   template <typename U>
314   friend bool operator==(const scoped_refptr<T>& lhs,
315                          const scoped_refptr<U>& rhs) {
316     return lhs.ptr_ == rhs.ptr_;
317   }
318 
319   // This operator is an optimization to avoid implicitly constructing a
320   // scoped_refptr<U> when comparing scoped_refptr against raw pointer. If the
321   // implicit conversion is ever removed this operator can also be removed.
322   template <typename U>
323   friend bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
324     return lhs.ptr_ == rhs;
325   }
326 
327   friend bool operator==(const scoped_refptr<T>& lhs, std::nullptr_t null) {
328     return !static_cast<bool>(lhs);
329   }
330 
331   template <typename U>
332   friend auto operator<=>(const scoped_refptr<T>& lhs,
333                           const scoped_refptr<U>& rhs) {
334     return lhs.ptr_ <=> rhs.ptr_;
335   }
336 
337   friend auto operator<=>(const scoped_refptr<T>& lhs, std::nullptr_t null) {
338     return lhs.ptr_ <=> static_cast<T*>(nullptr);
339   }
340 
341  protected:
342   // RAW_PTR_EXCLUSION: scoped_refptr<> has its own UaF prevention mechanism.
343   // Given how widespread it is, we it'll likely a perf regression for no
344   // additional security benefit.
345   RAW_PTR_EXCLUSION T* ptr_ = nullptr;
346 
347  private:
348   template <typename U>
349   friend scoped_refptr<U> base::AdoptRef(U*);
350   friend class ::base::SequencedTaskRunner;
351 
352   scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {}
353 
354   // Friend required for move constructors that set r.ptr_ to null.
355   template <typename U>
356   friend class scoped_refptr;
357 
358   // Non-inline helpers to allow:
359   //     class Opaque;
360   //     extern template class scoped_refptr<Opaque>;
361   // Otherwise the compiler will complain that Opaque is an incomplete type.
362   static void AddRef(T* ptr);
363   static void Release(T* ptr);
364 };
365 
366 template <typename T>
367 T* scoped_refptr<T>::release() {
368   T* ptr = ptr_;
369   ptr_ = nullptr;
370   return ptr;
371 }
372 
373 // static
374 template <typename T>
375 void scoped_refptr<T>::AddRef(T* ptr) {
376   base::subtle::AssertRefCountBaseMatches(ptr, ptr);
377   ptr->AddRef();
378 }
379 
380 // static
381 template <typename T>
382 void scoped_refptr<T>::Release(T* ptr) {
383   base::subtle::AssertRefCountBaseMatches(ptr, ptr);
384   ptr->Release();
385 }
386 
387 template <typename T>
388 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
389   return out << p.get();
390 }
391 
392 template <typename T>
393 void swap(scoped_refptr<T>& lhs, scoped_refptr<T>& rhs) noexcept {
394   lhs.swap(rhs);
395 }
396 
397 #endif  // BASE_MEMORY_SCOPED_REFPTR_H_
398