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