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