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