1 // Copyright 2020 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_POINTERS_RAW_PTR_H_ 6 #define PARTITION_ALLOC_POINTERS_RAW_PTR_H_ 7 8 #include <cstddef> 9 #include <cstdint> 10 #include <functional> 11 #include <type_traits> 12 #include <utility> 13 14 #include "build/build_config.h" 15 #include "partition_alloc/flags.h" 16 #include "partition_alloc/partition_alloc_base/compiler_specific.h" 17 #include "partition_alloc/partition_alloc_base/component_export.h" 18 #include "partition_alloc/partition_alloc_base/cxx20_is_constant_evaluated.h" 19 #include "partition_alloc/partition_alloc_base/debug/debugging_buildflags.h" 20 #include "partition_alloc/partition_alloc_buildflags.h" 21 #include "partition_alloc/partition_alloc_config.h" 22 #include "partition_alloc/partition_alloc_forward.h" 23 #include "partition_alloc/pointers/instance_tracer.h" 24 #include "partition_alloc/raw_ptr_buildflags.h" 25 26 #if BUILDFLAG(IS_WIN) 27 #include "partition_alloc/partition_alloc_base/win/win_handle_types.h" 28 #endif 29 30 #if BUILDFLAG(USE_PARTITION_ALLOC) 31 #include "partition_alloc/partition_alloc_base/check.h" 32 // Live implementation of MiraclePtr being built. 33 #if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) || \ 34 BUILDFLAG(USE_ASAN_BACKUP_REF_PTR) 35 #define PA_RAW_PTR_CHECK(condition) PA_BASE_CHECK(condition) 36 #else 37 // No-op implementation of MiraclePtr being built. 38 // Note that `PA_BASE_DCHECK()` evaporates from non-DCHECK builds, 39 // minimizing impact of generated code. 40 #define PA_RAW_PTR_CHECK(condition) PA_BASE_DCHECK(condition) 41 #endif // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) || 42 // BUILDFLAG(USE_ASAN_BACKUP_REF_PTR) 43 #else // BUILDFLAG(USE_PARTITION_ALLOC) 44 // Without PartitionAlloc, there's no `PA_BASE_D?CHECK()` implementation 45 // available. 46 #define PA_RAW_PTR_CHECK(condition) 47 #endif // BUILDFLAG(USE_PARTITION_ALLOC) 48 49 #if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) 50 #include "partition_alloc/pointers/raw_ptr_backup_ref_impl.h" 51 #elif BUILDFLAG(USE_ASAN_UNOWNED_PTR) 52 #include "partition_alloc/pointers/raw_ptr_asan_unowned_impl.h" 53 #elif BUILDFLAG(USE_HOOKABLE_RAW_PTR) 54 #include "partition_alloc/pointers/raw_ptr_hookable_impl.h" 55 #else 56 #include "partition_alloc/pointers/raw_ptr_noop_impl.h" 57 #endif 58 59 namespace cc { 60 class Scheduler; 61 } 62 namespace base::internal { 63 class DelayTimerBase; 64 } 65 namespace base::test { 66 struct RawPtrCountingImplForTest; 67 } 68 namespace content::responsiveness { 69 class Calculator; 70 } 71 72 namespace partition_alloc::internal { 73 74 // NOTE: All methods should be `PA_ALWAYS_INLINE`. raw_ptr is meant to be a 75 // lightweight replacement of a raw pointer, hence performance is critical. 76 77 // This is a bitfield representing the different flags that can be applied to a 78 // raw_ptr. 79 // 80 // Internal use only: Developers shouldn't use those values directly. 81 // 82 // Housekeeping rules: Try not to change trait values, so that numeric trait 83 // values stay constant across builds (could be useful e.g. when analyzing stack 84 // traces). A reasonable exception to this rule are `*ForTest` traits. As a 85 // matter of fact, we propose that new non-test traits are added before the 86 // `*ForTest` traits. 87 enum class RawPtrTraits : unsigned { 88 kEmpty = 0, 89 90 // Disables dangling pointer detection, but keeps other raw_ptr protections. 91 // 92 // Don't use directly, use DisableDanglingPtrDetection or DanglingUntriaged 93 // instead. 94 kMayDangle = (1 << 0), 95 96 // Disables any hooks, when building with BUILDFLAG(USE_HOOKABLE_RAW_PTR). 97 // 98 // Internal use only. 99 kDisableHooks = (1 << 2), 100 101 // Pointer arithmetic is discouraged and disabled by default. 102 // 103 // Don't use directly, use AllowPtrArithmetic instead. 104 kAllowPtrArithmetic = (1 << 3), 105 106 // This pointer has BRP disabled for experimental rewrites of containers. 107 // 108 // Don't use directly. 109 kDisableBRP = (1 << 4), 110 111 // Uninitialized pointers are discouraged and disabled by default. 112 // 113 // Don't use directly, use AllowUninitialized instead. 114 kAllowUninitialized = (1 << 5), 115 116 // *** ForTest traits below *** 117 118 // Adds accounting, on top of the NoOp implementation, for test purposes. 119 // raw_ptr/raw_ref with this trait perform extra bookkeeping, e.g. to track 120 // the number of times the raw_ptr is wrapped, unwrapped, etc. 121 // 122 // Test only. Include raw_ptr_counting_impl_for_test.h in your test 123 // files when using this trait. 124 kUseCountingImplForTest = (1 << 10), 125 126 // Helper trait that can be used to test raw_ptr's behaviour or conversions. 127 // 128 // Test only. 129 kDummyForTest = (1 << 11), 130 131 kAllMask = kMayDangle | kDisableHooks | kAllowPtrArithmetic | kDisableBRP | 132 kAllowUninitialized | kUseCountingImplForTest | kDummyForTest, 133 }; 134 // Template specialization to use |PA_DEFINE_OPERATORS_FOR_FLAGS| without 135 // |kMaxValue| declaration. 136 template <> 137 constexpr inline RawPtrTraits kAllFlags<RawPtrTraits> = RawPtrTraits::kAllMask; 138 139 PA_DEFINE_OPERATORS_FOR_FLAGS(RawPtrTraits); 140 141 } // namespace partition_alloc::internal 142 143 namespace base { 144 using partition_alloc::internal::RawPtrTraits; 145 146 namespace raw_ptr_traits { 147 148 // IsSupportedType<T>::value answers whether raw_ptr<T>: 149 // 1) compiles 150 // 2) is safe at runtime 151 // 152 // Templates that may end up using raw_ptr should use IsSupportedType to ensure 153 // that raw_ptr is not used with unsupported types. As an example, see how 154 // base::internal::Unretained(Ref)Wrapper uses IsSupportedType to decide whether 155 // it should use `raw_ptr<T>` or `T*`. 156 template <typename T, typename SFINAE = void> 157 struct IsSupportedType { 158 static constexpr bool value = true; 159 }; 160 161 // raw_ptr<T> is not compatible with function pointer types. Also, they don't 162 // even need the raw_ptr protection, because they don't point on heap. 163 template <typename T> 164 struct IsSupportedType<T, std::enable_if_t<std::is_function_v<T>>> { 165 static constexpr bool value = false; 166 }; 167 168 // This section excludes some types from raw_ptr<T> to avoid them from being 169 // used inside base::Unretained in performance sensitive places. These were 170 // identified from sampling profiler data. See crbug.com/1287151 for more info. 171 template <> 172 struct IsSupportedType<cc::Scheduler> { 173 static constexpr bool value = false; 174 }; 175 template <> 176 struct IsSupportedType<base::internal::DelayTimerBase> { 177 static constexpr bool value = false; 178 }; 179 template <> 180 struct IsSupportedType<content::responsiveness::Calculator> { 181 static constexpr bool value = false; 182 }; 183 184 #if __OBJC__ 185 // raw_ptr<T> is not compatible with pointers to Objective-C classes for a 186 // multitude of reasons. They may fail to compile in many cases, and wouldn't 187 // work well with tagged pointers. Anyway, Objective-C objects have their own 188 // way of tracking lifespan, hence don't need the raw_ptr protection as much. 189 // 190 // Such pointers are detected by checking if they're convertible to |id| type. 191 template <typename T> 192 struct IsSupportedType<T, std::enable_if_t<std::is_convertible_v<T*, id>>> { 193 static constexpr bool value = false; 194 }; 195 #endif // __OBJC__ 196 197 #if BUILDFLAG(IS_WIN) 198 // raw_ptr<HWND__> is unsafe at runtime - if the handle happens to also 199 // represent a valid pointer into a PartitionAlloc-managed region then it can 200 // lead to manipulating random memory when treating it as BackupRefPtr 201 // ref-count. See also https://crbug.com/1262017. 202 // 203 // TODO(https://crbug.com/1262017): Cover other handle types like HANDLE, 204 // HLOCAL, HINTERNET, or HDEVINFO. Maybe we should avoid using raw_ptr<T> when 205 // T=void (as is the case in these handle types). OTOH, explicit, 206 // non-template-based raw_ptr<void> should be allowed. Maybe this can be solved 207 // by having 2 traits: IsPointeeAlwaysSafe (to be used in templates) and 208 // IsPointeeUsuallySafe (to be used in the static_assert in raw_ptr). The 209 // upside of this approach is that it will safely handle base::Bind closing over 210 // HANDLE. The downside of this approach is that base::Bind closing over a 211 // void* pointer will not get UaF protection. 212 #define PA_WINDOWS_HANDLE_TYPE(name) \ 213 template <> \ 214 struct IsSupportedType<name##__, void> { \ 215 static constexpr bool value = false; \ 216 }; 217 #include "partition_alloc/partition_alloc_base/win/win_handle_types_list.inc" 218 #undef PA_WINDOWS_HANDLE_TYPE 219 #endif 220 221 #if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) 222 template <RawPtrTraits Traits> 223 using UnderlyingImplForTraits = internal::RawPtrBackupRefImpl< 224 /*AllowDangling=*/partition_alloc::internal::ContainsFlags( 225 Traits, 226 RawPtrTraits::kMayDangle), 227 /*DisableBRP=*/partition_alloc::internal::ContainsFlags( 228 Traits, 229 RawPtrTraits::kDisableBRP)>; 230 231 #elif BUILDFLAG(USE_ASAN_UNOWNED_PTR) 232 template <RawPtrTraits Traits> 233 using UnderlyingImplForTraits = internal::RawPtrAsanUnownedImpl< 234 partition_alloc::internal::ContainsFlags(Traits, 235 RawPtrTraits::kAllowPtrArithmetic), 236 partition_alloc::internal::ContainsFlags(Traits, RawPtrTraits::kMayDangle)>; 237 238 #elif BUILDFLAG(USE_HOOKABLE_RAW_PTR) 239 template <RawPtrTraits Traits> 240 using UnderlyingImplForTraits = internal::RawPtrHookableImpl< 241 /*EnableHooks=*/!partition_alloc::internal::ContainsFlags( 242 Traits, 243 RawPtrTraits::kDisableHooks)>; 244 245 #else 246 template <RawPtrTraits Traits> 247 using UnderlyingImplForTraits = internal::RawPtrNoOpImpl; 248 #endif 249 250 constexpr bool IsPtrArithmeticAllowed([[maybe_unused]] RawPtrTraits Traits) { 251 #if BUILDFLAG(ENABLE_POINTER_ARITHMETIC_TRAIT_CHECK) 252 return partition_alloc::internal::ContainsFlags( 253 Traits, RawPtrTraits::kAllowPtrArithmetic); 254 #else 255 return true; 256 #endif 257 } 258 259 // ImplForTraits is the struct that implements raw_ptr functions. Think of 260 // raw_ptr as a thin wrapper, that directs calls to ImplForTraits. ImplForTraits 261 // may be different from UnderlyingImplForTraits, because it may select a 262 // test impl instead. 263 template <RawPtrTraits Traits> 264 using ImplForTraits = 265 std::conditional_t<partition_alloc::internal::ContainsFlags( 266 Traits, 267 RawPtrTraits::kUseCountingImplForTest), 268 test::RawPtrCountingImplForTest, 269 UnderlyingImplForTraits<Traits>>; 270 271 // `kTypeTraits` is a customization interface to accosiate `T` with some 272 // `RawPtrTraits`. Users may create specialization of this variable 273 // to enable some traits by default. 274 // Note that specialization must be declared before the first use that would 275 // cause implicit instantiation of `raw_ptr` or `raw_ref`, in every translation 276 // unit where such use occurs. 277 template <typename T, typename SFINAE = void> 278 constexpr inline auto kTypeTraits = RawPtrTraits::kEmpty; 279 280 } // namespace raw_ptr_traits 281 282 // `raw_ptr<T>` is a non-owning smart pointer that has improved memory-safety 283 // over raw pointers. See the documentation for details: 284 // https://source.chromium.org/chromium/chromium/src/+/main:base/memory/raw_ptr.md 285 // 286 // raw_ptr<T> is marked as [[gsl::Pointer]] which allows the compiler to catch 287 // some bugs where the raw_ptr holds a dangling pointer to a temporary object. 288 // However the [[gsl::Pointer]] analysis expects that such types do not have a 289 // non-default move constructor/assignment. Thus, it's possible to get an error 290 // where the pointer is not actually dangling, and have to work around the 291 // compiler. We have not managed to construct such an example in Chromium yet. 292 template <typename T, RawPtrTraits PointerTraits = RawPtrTraits::kEmpty> 293 class PA_TRIVIAL_ABI PA_GSL_POINTER raw_ptr { 294 public: 295 // Users may specify `RawPtrTraits` via raw_ptr's second template parameter 296 // `PointerTraits`, or specialization of `raw_ptr_traits::kTypeTraits<T>`. 297 constexpr static auto Traits = PointerTraits | raw_ptr_traits::kTypeTraits<T>; 298 using Impl = typename raw_ptr_traits::ImplForTraits<Traits>; 299 // Needed to make gtest Pointee matcher work with raw_ptr. 300 using element_type = T; 301 using DanglingType = raw_ptr<T, Traits | RawPtrTraits::kMayDangle>; 302 303 #if !BUILDFLAG(USE_PARTITION_ALLOC) 304 // See comment at top about `PA_RAW_PTR_CHECK()`. 305 static_assert(std::is_same_v<Impl, internal::RawPtrNoOpImpl>); 306 #endif // !BUILDFLAG(USE_PARTITION_ALLOC) 307 308 static_assert(partition_alloc::internal::AreValidFlags(Traits), 309 "Unknown raw_ptr trait(s)"); 310 static_assert(raw_ptr_traits::IsSupportedType<T>::value, 311 "raw_ptr<T> doesn't work with this kind of pointee type T"); 312 313 static constexpr bool kZeroOnConstruct = 314 Impl::kMustZeroOnConstruct || (BUILDFLAG(RAW_PTR_ZERO_ON_CONSTRUCT) && 315 !partition_alloc::internal::ContainsFlags( 316 Traits, 317 RawPtrTraits::kAllowUninitialized)); 318 static constexpr bool kZeroOnMove = 319 Impl::kMustZeroOnMove || BUILDFLAG(RAW_PTR_ZERO_ON_MOVE); 320 static constexpr bool kZeroOnDestruct = 321 Impl::kMustZeroOnDestruct || BUILDFLAG(RAW_PTR_ZERO_ON_DESTRUCT); 322 323 // A non-trivial default ctor is required for complex implementations (e.g. 324 // BackupRefPtr), or even for NoOpImpl when zeroing is requested. 325 #if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) || \ 326 BUILDFLAG(USE_ASAN_UNOWNED_PTR) || BUILDFLAG(USE_HOOKABLE_RAW_PTR) || \ 327 BUILDFLAG(RAW_PTR_ZERO_ON_CONSTRUCT) 328 PA_ALWAYS_INLINE constexpr raw_ptr() noexcept { 329 if constexpr (kZeroOnConstruct) { 330 wrapped_ptr_ = nullptr; 331 } 332 } 333 #else 334 // raw_ptr can be trivially default constructed (leaving |wrapped_ptr_| 335 // uninitialized). 336 PA_ALWAYS_INLINE constexpr raw_ptr() noexcept = default; 337 static_assert(!kZeroOnConstruct); 338 #endif // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) || 339 // BUILDFLAG(USE_ASAN_UNOWNED_PTR) || BUILDFLAG(USE_HOOKABLE_RAW_PTR) || 340 // BUILDFLAG(RAW_PTR_ZERO_ON_CONSTRUCT) 341 342 // A non-trivial copy ctor and assignment operator are required for complex 343 // implementations (e.g. BackupRefPtr). Unlike the blocks around, we don't need 344 // these for NoOpImpl even when zeroing is requested; better to keep them 345 // trivial. 346 #if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) || \ 347 BUILDFLAG(USE_ASAN_UNOWNED_PTR) || BUILDFLAG(USE_HOOKABLE_RAW_PTR) 348 PA_ALWAYS_INLINE constexpr raw_ptr(const raw_ptr& p) noexcept 349 : wrapped_ptr_(Impl::Duplicate(p.wrapped_ptr_)) { 350 Impl::Trace(tracer_.owner_id(), p.wrapped_ptr_); 351 } 352 353 PA_ALWAYS_INLINE constexpr raw_ptr& operator=(const raw_ptr& p) noexcept { 354 // Duplicate before releasing, in case the pointer is assigned to itself. 355 // 356 // Unlike the move version of this operator, don't add |this != &p| branch, 357 // for performance reasons. Self-assignment is rare, so unconditionally 358 // calling `Duplicate()` is almost certainly cheaper than adding an 359 // additional branch, even if always correctly predicted. 360 T* new_ptr = Impl::Duplicate(p.wrapped_ptr_); 361 Impl::ReleaseWrappedPtr(wrapped_ptr_); 362 Impl::Untrace(tracer_.owner_id()); 363 wrapped_ptr_ = new_ptr; 364 Impl::Trace(tracer_.owner_id(), wrapped_ptr_); 365 return *this; 366 } 367 #else 368 PA_ALWAYS_INLINE raw_ptr(const raw_ptr&) noexcept = default; 369 PA_ALWAYS_INLINE raw_ptr& operator=(const raw_ptr&) noexcept = default; 370 #endif // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) || 371 // BUILDFLAG(USE_ASAN_UNOWNED_PTR) || BUILDFLAG(USE_HOOKABLE_RAW_PTR) 372 373 // A non-trivial move ctor and assignment operator are required for complex 374 // implementations (e.g. BackupRefPtr), or even for NoOpImpl when zeroing is 375 // requested. 376 #if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) || \ 377 BUILDFLAG(USE_ASAN_UNOWNED_PTR) || BUILDFLAG(USE_HOOKABLE_RAW_PTR) || \ 378 BUILDFLAG(RAW_PTR_ZERO_ON_MOVE) 379 PA_ALWAYS_INLINE constexpr raw_ptr(raw_ptr&& p) noexcept { 380 wrapped_ptr_ = p.wrapped_ptr_; 381 Impl::Trace(tracer_.owner_id(), wrapped_ptr_); 382 if constexpr (kZeroOnMove) { 383 p.wrapped_ptr_ = nullptr; 384 Impl::Untrace(p.tracer_.owner_id()); 385 } 386 } 387 PA_ALWAYS_INLINE constexpr raw_ptr& operator=(raw_ptr&& p) noexcept { 388 // Unlike the the copy version of this operator, this branch is necessary 389 // for correctness. 390 if (PA_LIKELY(this != &p)) { 391 Impl::ReleaseWrappedPtr(wrapped_ptr_); 392 Impl::Untrace(tracer_.owner_id()); 393 wrapped_ptr_ = p.wrapped_ptr_; 394 Impl::Trace(tracer_.owner_id(), wrapped_ptr_); 395 if constexpr (kZeroOnMove) { 396 p.wrapped_ptr_ = nullptr; 397 Impl::Untrace(p.tracer_.owner_id()); 398 } 399 } 400 return *this; 401 } 402 #else 403 PA_ALWAYS_INLINE raw_ptr(raw_ptr&&) noexcept = default; 404 PA_ALWAYS_INLINE raw_ptr& operator=(raw_ptr&&) noexcept = default; 405 static_assert(!kZeroOnMove); 406 #endif // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) || 407 // BUILDFLAG(USE_ASAN_UNOWNED_PTR) || BUILDFLAG(USE_HOOKABLE_RAW_PTR) || 408 // BUILDFLAG(RAW_PTR_ZERO_ON_MOVE) 409 410 // A non-trivial default dtor is required for complex implementations (e.g. 411 // BackupRefPtr), or even for NoOpImpl when zeroing is requested. 412 #if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) || \ 413 BUILDFLAG(USE_ASAN_UNOWNED_PTR) || BUILDFLAG(USE_HOOKABLE_RAW_PTR) || \ 414 BUILDFLAG(RAW_PTR_ZERO_ON_DESTRUCT) 415 PA_ALWAYS_INLINE PA_CONSTEXPR_DTOR ~raw_ptr() noexcept { 416 Impl::ReleaseWrappedPtr(wrapped_ptr_); 417 Impl::Untrace(tracer_.owner_id()); 418 // Work around external issues where raw_ptr is used after destruction. 419 if constexpr (kZeroOnDestruct) { 420 wrapped_ptr_ = nullptr; 421 } 422 } 423 #else 424 PA_ALWAYS_INLINE ~raw_ptr() noexcept = default; 425 static_assert(!kZeroOnDestruct); 426 #endif // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) || 427 // BUILDFLAG(USE_ASAN_UNOWNED_PTR) || BUILDFLAG(USE_HOOKABLE_RAW_PTR) || 428 // BUILDFLAG(RAW_PTR_ZERO_ON_DESTRUCT) 429 430 // Cross-kind copy constructor. 431 // Move is not supported as different traits may use different ref-counts, so 432 // let move operations degrade to copy, which handles it well. 433 template <RawPtrTraits PassedTraits, 434 typename = std::enable_if_t<Traits != PassedTraits>> 435 PA_ALWAYS_INLINE constexpr explicit raw_ptr( 436 const raw_ptr<T, PassedTraits>& p) noexcept 437 : wrapped_ptr_(Impl::WrapRawPtrForDuplication( 438 raw_ptr_traits::ImplForTraits<raw_ptr<T, PassedTraits>::Traits>:: 439 UnsafelyUnwrapPtrForDuplication(p.wrapped_ptr_))) { 440 Impl::Trace(tracer_.owner_id(), wrapped_ptr_); 441 // Limit cross-kind conversions only to cases where `kMayDangle` gets added, 442 // because that's needed for ExtractAsDangling() and Unretained(Ref)Wrapper. 443 // Use a static_assert, instead of disabling via SFINAE, so that the 444 // compiler catches other conversions. Otherwise the implicit 445 // `raw_ptr<T> -> T* -> raw_ptr<>` route will be taken. 446 static_assert(Traits == (raw_ptr<T, PassedTraits>::Traits | 447 RawPtrTraits::kMayDangle)); 448 } 449 450 // Cross-kind assignment. 451 // Move is not supported as different traits may use different ref-counts, so 452 // let move operations degrade to copy, which handles it well. 453 template <RawPtrTraits PassedTraits, 454 typename = std::enable_if_t<Traits != PassedTraits>> 455 PA_ALWAYS_INLINE constexpr raw_ptr& operator=( 456 const raw_ptr<T, PassedTraits>& p) noexcept { 457 // Limit cross-kind assignments only to cases where `kMayDangle` gets added, 458 // because that's needed for ExtractAsDangling() and Unretained(Ref)Wrapper. 459 // Use a static_assert, instead of disabling via SFINAE, so that the 460 // compiler catches other conversions. Otherwise the implicit 461 // `raw_ptr<T> -> T* -> raw_ptr<>` route will be taken. 462 static_assert(Traits == (raw_ptr<T, PassedTraits>::Traits | 463 RawPtrTraits::kMayDangle)); 464 465 Impl::ReleaseWrappedPtr(wrapped_ptr_); 466 Impl::Untrace(tracer_.owner_id()); 467 wrapped_ptr_ = Impl::WrapRawPtrForDuplication( 468 raw_ptr_traits::ImplForTraits<raw_ptr<T, PassedTraits>::Traits>:: 469 UnsafelyUnwrapPtrForDuplication(p.wrapped_ptr_)); 470 Impl::Trace(tracer_.owner_id(), wrapped_ptr_); 471 return *this; 472 } 473 474 // Deliberately implicit, because raw_ptr is supposed to resemble raw ptr. 475 // Ignore kZeroOnConstruct, because here the caller explicitly wishes to 476 // initialize with nullptr. 477 // NOLINTNEXTLINE(google-explicit-constructor) 478 PA_ALWAYS_INLINE constexpr raw_ptr(std::nullptr_t) noexcept 479 : wrapped_ptr_(nullptr) {} 480 481 // Deliberately implicit, because raw_ptr is supposed to resemble raw ptr. 482 // NOLINTNEXTLINE(google-explicit-constructor) 483 PA_ALWAYS_INLINE constexpr raw_ptr(T* p) noexcept 484 : wrapped_ptr_(Impl::WrapRawPtr(p)) { 485 Impl::Trace(tracer_.owner_id(), wrapped_ptr_); 486 } 487 488 // Deliberately implicit in order to support implicit upcast. 489 template <typename U, 490 typename = std::enable_if_t< 491 std::is_convertible_v<U*, T*> && 492 !std::is_void_v<typename std::remove_cv<T>::type>>> 493 // NOLINTNEXTLINE(google-explicit-constructor) 494 PA_ALWAYS_INLINE constexpr raw_ptr(const raw_ptr<U, Traits>& ptr) noexcept 495 : wrapped_ptr_( 496 Impl::Duplicate(Impl::template Upcast<T, U>(ptr.wrapped_ptr_))) { 497 Impl::Trace(tracer_.owner_id(), wrapped_ptr_); 498 } 499 // Deliberately implicit in order to support implicit upcast. 500 template <typename U, 501 typename = std::enable_if_t< 502 std::is_convertible_v<U*, T*> && 503 !std::is_void_v<typename std::remove_cv<T>::type>>> 504 // NOLINTNEXTLINE(google-explicit-constructor) 505 PA_ALWAYS_INLINE constexpr raw_ptr(raw_ptr<U, Traits>&& ptr) noexcept 506 : wrapped_ptr_(Impl::template Upcast<T, U>(ptr.wrapped_ptr_)) { 507 Impl::Trace(tracer_.owner_id(), wrapped_ptr_); 508 if constexpr (kZeroOnMove) { 509 ptr.wrapped_ptr_ = nullptr; 510 Impl::Untrace(ptr.tracer_.owner_id()); 511 } 512 } 513 514 PA_ALWAYS_INLINE constexpr raw_ptr& operator=(std::nullptr_t) noexcept { 515 Impl::ReleaseWrappedPtr(wrapped_ptr_); 516 Impl::Untrace(tracer_.owner_id()); 517 wrapped_ptr_ = nullptr; 518 return *this; 519 } 520 PA_ALWAYS_INLINE constexpr raw_ptr& operator=(T* p) noexcept { 521 Impl::ReleaseWrappedPtr(wrapped_ptr_); 522 Impl::Untrace(tracer_.owner_id()); 523 wrapped_ptr_ = Impl::WrapRawPtr(p); 524 Impl::Trace(tracer_.owner_id(), wrapped_ptr_); 525 return *this; 526 } 527 528 // Upcast assignment 529 template <typename U, 530 typename = std::enable_if_t< 531 std::is_convertible_v<U*, T*> && 532 !std::is_void_v<typename std::remove_cv<T>::type>>> 533 PA_ALWAYS_INLINE constexpr raw_ptr& operator=( 534 const raw_ptr<U, Traits>& ptr) noexcept { 535 // Make sure that pointer isn't assigned to itself (look at raw_ptr address, 536 // not its contained pointer value). The comparison is only needed when they 537 // are the same type, otherwise they can't be the same raw_ptr object. 538 #if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS) 539 if constexpr (std::is_same_v<raw_ptr, std::decay_t<decltype(ptr)>>) { 540 PA_RAW_PTR_CHECK(this != &ptr); 541 } 542 #endif 543 Impl::ReleaseWrappedPtr(wrapped_ptr_); 544 Impl::Untrace(tracer_.owner_id()); 545 wrapped_ptr_ = 546 Impl::Duplicate(Impl::template Upcast<T, U>(ptr.wrapped_ptr_)); 547 Impl::Trace(tracer_.owner_id(), wrapped_ptr_); 548 return *this; 549 } 550 template <typename U, 551 typename = std::enable_if_t< 552 std::is_convertible_v<U*, T*> && 553 !std::is_void_v<typename std::remove_cv<T>::type>>> 554 PA_ALWAYS_INLINE constexpr raw_ptr& operator=( 555 raw_ptr<U, Traits>&& ptr) noexcept { 556 // Make sure that pointer isn't assigned to itself (look at raw_ptr address, 557 // not its contained pointer value). The comparison is only needed when they 558 // are the same type, otherwise they can't be the same raw_ptr object. 559 #if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS) 560 if constexpr (std::is_same_v<raw_ptr, std::decay_t<decltype(ptr)>>) { 561 PA_RAW_PTR_CHECK(this != &ptr); 562 } 563 #endif 564 Impl::ReleaseWrappedPtr(wrapped_ptr_); 565 Impl::Untrace(tracer_.owner_id()); 566 wrapped_ptr_ = Impl::template Upcast<T, U>(ptr.wrapped_ptr_); 567 Impl::Trace(tracer_.owner_id(), wrapped_ptr_); 568 if constexpr (kZeroOnMove) { 569 ptr.wrapped_ptr_ = nullptr; 570 Impl::Untrace(ptr.tracer_.owner_id()); 571 } 572 return *this; 573 } 574 575 // Avoid using. The goal of raw_ptr is to be as close to raw pointer as 576 // possible, so use it only if absolutely necessary (e.g. for const_cast). 577 PA_ALWAYS_INLINE constexpr T* get() const { return GetForExtraction(); } 578 579 // You may use |raw_ptr<T>::AsEphemeralRawAddr()| to obtain |T**| or |T*&| 580 // from |raw_ptr<T>|, as long as you follow these requirements: 581 // - DO NOT carry T**/T*& obtained via AsEphemeralRawAddr() out of 582 // expression. 583 // - DO NOT use raw_ptr or T**/T*& multiple times within an expression. 584 // 585 // https://chromium.googlesource.com/chromium/src/+/main/base/memory/raw_ptr.md#in_out-arguments-need-to-be-refactored 586 class EphemeralRawAddr { 587 public: 588 EphemeralRawAddr(const EphemeralRawAddr&) = delete; 589 EphemeralRawAddr& operator=(const EphemeralRawAddr&) = delete; 590 void* operator new(size_t) = delete; 591 void* operator new(size_t, void*) = delete; 592 PA_ALWAYS_INLINE PA_CONSTEXPR_DTOR ~EphemeralRawAddr() { original = copy; } 593 594 PA_ALWAYS_INLINE constexpr T** operator&() && PA_LIFETIME_BOUND { 595 return © 596 } 597 // NOLINTNEXTLINE(google-explicit-constructor) 598 PA_ALWAYS_INLINE constexpr operator T*&() && PA_LIFETIME_BOUND { 599 return copy; 600 } 601 602 private: 603 friend class raw_ptr; 604 PA_ALWAYS_INLINE constexpr explicit EphemeralRawAddr(raw_ptr& ptr) 605 : copy(ptr.get()), original(ptr) {} 606 T* copy; 607 raw_ptr& original; // Original pointer. 608 }; 609 PA_ALWAYS_INLINE PA_CONSTEXPR_DTOR EphemeralRawAddr AsEphemeralRawAddr() & { 610 return EphemeralRawAddr(*this); 611 } 612 613 PA_ALWAYS_INLINE constexpr explicit operator bool() const { 614 return !!wrapped_ptr_; 615 } 616 617 template <typename U = T, 618 typename = std::enable_if_t< 619 !std::is_void_v<typename std::remove_cv<U>::type>>> 620 PA_ALWAYS_INLINE constexpr U& operator*() const { 621 return *GetForDereference(); 622 } 623 PA_ALWAYS_INLINE constexpr T* operator->() const { 624 return GetForDereference(); 625 } 626 627 // Deliberately implicit, because raw_ptr is supposed to resemble raw ptr. 628 // NOLINTNEXTLINE(google-explicit-constructor) 629 PA_ALWAYS_INLINE constexpr operator T*() const { return GetForExtraction(); } 630 template <typename U> 631 PA_ALWAYS_INLINE constexpr explicit operator U*() const { 632 // This operator may be invoked from static_cast, meaning the types may not 633 // be implicitly convertible, hence the need for static_cast here. 634 return static_cast<U*>(GetForExtraction()); 635 } 636 637 PA_ALWAYS_INLINE constexpr raw_ptr& operator++() { 638 static_assert( 639 raw_ptr_traits::IsPtrArithmeticAllowed(Traits), 640 "cannot increment raw_ptr unless AllowPtrArithmetic trait is present."); 641 wrapped_ptr_ = Impl::Advance(wrapped_ptr_, 1, true); 642 return *this; 643 } 644 PA_ALWAYS_INLINE constexpr raw_ptr& operator--() { 645 static_assert( 646 raw_ptr_traits::IsPtrArithmeticAllowed(Traits), 647 "cannot decrement raw_ptr unless AllowPtrArithmetic trait is present."); 648 wrapped_ptr_ = Impl::Retreat(wrapped_ptr_, 1, true); 649 return *this; 650 } 651 PA_ALWAYS_INLINE constexpr raw_ptr operator++(int /* post_increment */) { 652 static_assert( 653 raw_ptr_traits::IsPtrArithmeticAllowed(Traits), 654 "cannot increment raw_ptr unless AllowPtrArithmetic trait is present."); 655 raw_ptr result = *this; 656 ++(*this); 657 return result; 658 } 659 PA_ALWAYS_INLINE constexpr raw_ptr operator--(int /* post_decrement */) { 660 static_assert( 661 raw_ptr_traits::IsPtrArithmeticAllowed(Traits), 662 "cannot decrement raw_ptr unless AllowPtrArithmetic trait is present."); 663 raw_ptr result = *this; 664 --(*this); 665 return result; 666 } 667 template < 668 typename Z, 669 typename = std::enable_if_t<partition_alloc::internal::is_offset_type<Z>>> 670 PA_ALWAYS_INLINE constexpr raw_ptr& operator+=(Z delta_elems) { 671 static_assert( 672 raw_ptr_traits::IsPtrArithmeticAllowed(Traits), 673 "cannot increment raw_ptr unless AllowPtrArithmetic trait is present."); 674 wrapped_ptr_ = Impl::Advance(wrapped_ptr_, delta_elems, true); 675 return *this; 676 } 677 template < 678 typename Z, 679 typename = std::enable_if_t<partition_alloc::internal::is_offset_type<Z>>> 680 PA_ALWAYS_INLINE constexpr raw_ptr& operator-=(Z delta_elems) { 681 static_assert( 682 raw_ptr_traits::IsPtrArithmeticAllowed(Traits), 683 "cannot decrement raw_ptr unless AllowPtrArithmetic trait is present."); 684 wrapped_ptr_ = Impl::Retreat(wrapped_ptr_, delta_elems, true); 685 return *this; 686 } 687 688 template <typename Z, 689 typename U = T, 690 typename = std::enable_if_t< 691 !std::is_void_v<typename std::remove_cv<U>::type> && 692 partition_alloc::internal::is_offset_type<Z>>> 693 PA_ALWAYS_INLINE constexpr U& operator[](Z delta_elems) const { 694 static_assert( 695 raw_ptr_traits::IsPtrArithmeticAllowed(Traits), 696 "cannot index raw_ptr unless AllowPtrArithmetic trait is present."); 697 // Call SafelyUnwrapPtrForDereference() to simulate what GetForDereference() 698 // does, but without creating a temporary. 699 return *Impl::SafelyUnwrapPtrForDereference( 700 Impl::Advance(wrapped_ptr_, delta_elems, false)); 701 } 702 703 // Do not disable operator+() and operator-(). 704 // They provide OOB checks, which prevent from assigning an arbitrary value to 705 // raw_ptr, leading BRP to modifying arbitrary memory thinking it's ref-count. 706 // Keep them enabled, which may be blocked later when attempting to apply the 707 // += or -= operation, when disabled. In the absence of operators +/-, the 708 // compiler is free to implicitly convert to the underlying T* representation 709 // and perform ordinary pointer arithmetic, thus invalidating the purpose 710 // behind disabling them. 711 // 712 // For example, disabling these when `!is_offset_type<Z>` would remove the 713 // operators for Z=uint64_t on 32-bit systems. The compiler instead would 714 // generate code that converts `raw_ptr<T>` to `T*` and adds uint64_t to that, 715 // bypassing the OOB protection entirely. 716 template <typename Z> 717 PA_ALWAYS_INLINE friend constexpr raw_ptr operator+(const raw_ptr& p, 718 Z delta_elems) { 719 // Don't check `is_offset_type<Z>` here, as existence of `Advance` is 720 // already gated on that, and we'd get double errors. 721 static_assert( 722 raw_ptr_traits::IsPtrArithmeticAllowed(Traits), 723 "cannot add to raw_ptr unless AllowPtrArithmetic trait is present."); 724 raw_ptr result = Impl::Advance(p.wrapped_ptr_, delta_elems, false); 725 return result; 726 } 727 template <typename Z> 728 PA_ALWAYS_INLINE friend constexpr raw_ptr operator+(Z delta_elems, 729 const raw_ptr& p) { 730 return p + delta_elems; 731 } 732 template <typename Z> 733 PA_ALWAYS_INLINE friend constexpr raw_ptr operator-(const raw_ptr& p, 734 Z delta_elems) { 735 // Don't check `is_offset_type<Z>` here, as existence of `Retreat` is 736 // already gated on that, and we'd get double errors. 737 static_assert(raw_ptr_traits::IsPtrArithmeticAllowed(Traits), 738 "cannot subtract from raw_ptr unless AllowPtrArithmetic " 739 "trait is present."); 740 raw_ptr result = Impl::Retreat(p.wrapped_ptr_, delta_elems, false); 741 return result; 742 } 743 744 // The "Do not disable operator+() and operator-()" comment above doesn't 745 // apply to the delta operator-() below. 746 PA_ALWAYS_INLINE friend constexpr ptrdiff_t operator-(const raw_ptr& p1, 747 const raw_ptr& p2) { 748 static_assert( 749 raw_ptr_traits::IsPtrArithmeticAllowed(Traits), 750 "cannot subtract raw_ptrs unless AllowPtrArithmetic trait is present."); 751 return Impl::GetDeltaElems(p1.wrapped_ptr_, p2.wrapped_ptr_); 752 } 753 PA_ALWAYS_INLINE friend constexpr ptrdiff_t operator-(T* p1, 754 const raw_ptr& p2) { 755 static_assert( 756 raw_ptr_traits::IsPtrArithmeticAllowed(Traits), 757 "cannot subtract raw_ptrs unless AllowPtrArithmetic trait is present."); 758 return Impl::GetDeltaElems(p1, p2.wrapped_ptr_); 759 } 760 PA_ALWAYS_INLINE friend constexpr ptrdiff_t operator-(const raw_ptr& p1, 761 T* p2) { 762 static_assert( 763 raw_ptr_traits::IsPtrArithmeticAllowed(Traits), 764 "cannot subtract raw_ptrs unless AllowPtrArithmetic trait is present."); 765 return Impl::GetDeltaElems(p1.wrapped_ptr_, p2); 766 } 767 768 // Stop referencing the underlying pointer and free its memory. Compared to 769 // raw delete calls, this avoids the raw_ptr to be temporarily dangling 770 // during the free operation, which will lead to taking the slower path that 771 // involves quarantine. 772 PA_ALWAYS_INLINE constexpr void ClearAndDelete() noexcept { 773 delete GetForExtractionAndReset(); 774 } 775 PA_ALWAYS_INLINE constexpr void ClearAndDeleteArray() noexcept { 776 delete[] GetForExtractionAndReset(); 777 } 778 779 // Clear the underlying pointer and return another raw_ptr instance 780 // that is allowed to dangle. 781 // This can be useful in cases such as: 782 // ``` 783 // ptr.ExtractAsDangling()->SelfDestroy(); 784 // ``` 785 // ``` 786 // c_style_api_do_something_and_destroy(ptr.ExtractAsDangling()); 787 // ``` 788 // NOTE, avoid using this method as it indicates an error-prone memory 789 // ownership pattern. If possible, use smart pointers like std::unique_ptr<> 790 // instead of raw_ptr<>. 791 // If you have to use it, avoid saving the return value in a long-lived 792 // variable (or worse, a field)! It's meant to be used as a temporary, to be 793 // passed into a cleanup & freeing function, and destructed at the end of the 794 // statement. 795 PA_ALWAYS_INLINE constexpr DanglingType ExtractAsDangling() noexcept { 796 DanglingType res(std::move(*this)); 797 // Not all implementation clear the source pointer on move. Furthermore, 798 // even for implemtantions that do, cross-kind conversions (that add 799 // kMayDangle) fall back to a copy, instead of move. So do it here just in 800 // case. Should be cheap. 801 operator=(nullptr); 802 return res; 803 } 804 805 // Comparison operators between raw_ptr and raw_ptr<U>/U*/std::nullptr_t. 806 // Strictly speaking, it is not necessary to provide these: the compiler can 807 // use the conversion operator implicitly to allow comparisons to fall back to 808 // comparisons between raw pointers. However, `operator T*`/`operator U*` may 809 // perform safety checks with a higher runtime cost, so to avoid this, provide 810 // explicit comparison operators for all combinations of parameters. 811 812 // Comparisons between `raw_ptr`s. This unusual declaration and separate 813 // definition below is because `GetForComparison()` is a private method. The 814 // more conventional approach of defining a comparison operator between 815 // `raw_ptr` and `raw_ptr<U>` in the friend declaration itself does not work, 816 // because a comparison operator defined inline would not be allowed to call 817 // `raw_ptr<U>`'s private `GetForComparison()` method. 818 template <typename U, typename V, RawPtrTraits R1, RawPtrTraits R2> 819 friend constexpr bool operator==(const raw_ptr<U, R1>& lhs, 820 const raw_ptr<V, R2>& rhs); 821 template <typename U, typename V, RawPtrTraits R1, RawPtrTraits R2> 822 friend constexpr bool operator!=(const raw_ptr<U, R1>& lhs, 823 const raw_ptr<V, R2>& rhs); 824 template <typename U, typename V, RawPtrTraits R1, RawPtrTraits R2> 825 friend constexpr bool operator<(const raw_ptr<U, R1>& lhs, 826 const raw_ptr<V, R2>& rhs); 827 template <typename U, typename V, RawPtrTraits R1, RawPtrTraits R2> 828 friend constexpr bool operator>(const raw_ptr<U, R1>& lhs, 829 const raw_ptr<V, R2>& rhs); 830 template <typename U, typename V, RawPtrTraits R1, RawPtrTraits R2> 831 friend constexpr bool operator<=(const raw_ptr<U, R1>& lhs, 832 const raw_ptr<V, R2>& rhs); 833 template <typename U, typename V, RawPtrTraits R1, RawPtrTraits R2> 834 friend constexpr bool operator>=(const raw_ptr<U, R1>& lhs, 835 const raw_ptr<V, R2>& rhs); 836 837 // Comparisons with U*. These operators also handle the case where the RHS is 838 // T*. 839 template <typename U> 840 PA_ALWAYS_INLINE friend constexpr bool operator==(const raw_ptr& lhs, 841 U* rhs) { 842 return lhs.GetForComparison() == rhs; 843 } 844 template <typename U> 845 PA_ALWAYS_INLINE friend constexpr bool operator!=(const raw_ptr& lhs, 846 U* rhs) { 847 return !(lhs == rhs); 848 } 849 template <typename U> 850 PA_ALWAYS_INLINE friend constexpr bool operator==(U* lhs, 851 const raw_ptr& rhs) { 852 return rhs == lhs; // Reverse order to call the operator above. 853 } 854 template <typename U> 855 PA_ALWAYS_INLINE friend constexpr bool operator!=(U* lhs, 856 const raw_ptr& rhs) { 857 return rhs != lhs; // Reverse order to call the operator above. 858 } 859 template <typename U> 860 PA_ALWAYS_INLINE friend constexpr bool operator<(const raw_ptr& lhs, U* rhs) { 861 return lhs.GetForComparison() < rhs; 862 } 863 template <typename U> 864 PA_ALWAYS_INLINE friend constexpr bool operator<=(const raw_ptr& lhs, 865 U* rhs) { 866 return lhs.GetForComparison() <= rhs; 867 } 868 template <typename U> 869 PA_ALWAYS_INLINE friend constexpr bool operator>(const raw_ptr& lhs, U* rhs) { 870 return lhs.GetForComparison() > rhs; 871 } 872 template <typename U> 873 PA_ALWAYS_INLINE friend constexpr bool operator>=(const raw_ptr& lhs, 874 U* rhs) { 875 return lhs.GetForComparison() >= rhs; 876 } 877 template <typename U> 878 PA_ALWAYS_INLINE friend constexpr bool operator<(U* lhs, const raw_ptr& rhs) { 879 return lhs < rhs.GetForComparison(); 880 } 881 template <typename U> 882 PA_ALWAYS_INLINE friend constexpr bool operator<=(U* lhs, 883 const raw_ptr& rhs) { 884 return lhs <= rhs.GetForComparison(); 885 } 886 template <typename U> 887 PA_ALWAYS_INLINE friend constexpr bool operator>(U* lhs, const raw_ptr& rhs) { 888 return lhs > rhs.GetForComparison(); 889 } 890 template <typename U> 891 PA_ALWAYS_INLINE friend constexpr bool operator>=(U* lhs, 892 const raw_ptr& rhs) { 893 return lhs >= rhs.GetForComparison(); 894 } 895 896 // Comparisons with `std::nullptr_t`. 897 PA_ALWAYS_INLINE friend constexpr bool operator==(const raw_ptr& lhs, 898 std::nullptr_t) { 899 return !lhs; 900 } 901 PA_ALWAYS_INLINE friend constexpr bool operator!=(const raw_ptr& lhs, 902 std::nullptr_t) { 903 return !!lhs; // Use !! otherwise the costly implicit cast will be used. 904 } 905 PA_ALWAYS_INLINE friend constexpr bool operator==(std::nullptr_t, 906 const raw_ptr& rhs) { 907 return !rhs; 908 } 909 PA_ALWAYS_INLINE friend constexpr bool operator!=(std::nullptr_t, 910 const raw_ptr& rhs) { 911 return !!rhs; // Use !! otherwise the costly implicit cast will be used. 912 } 913 914 PA_ALWAYS_INLINE friend constexpr void swap(raw_ptr& lhs, 915 raw_ptr& rhs) noexcept { 916 Impl::IncrementSwapCountForTest(); 917 std::swap(lhs.wrapped_ptr_, rhs.wrapped_ptr_); 918 } 919 920 PA_ALWAYS_INLINE void ReportIfDangling() const noexcept { 921 #if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) 922 Impl::ReportIfDangling(wrapped_ptr_); 923 #endif 924 } 925 926 private: 927 // This getter is meant for situations where the pointer is meant to be 928 // dereferenced. It is allowed to crash on nullptr (it may or may not), 929 // because it knows that the caller will crash on nullptr. 930 PA_ALWAYS_INLINE constexpr T* GetForDereference() const { 931 return Impl::SafelyUnwrapPtrForDereference(wrapped_ptr_); 932 } 933 // This getter is meant for situations where the raw pointer is meant to be 934 // extracted outside of this class, but not necessarily with an intention to 935 // dereference. It mustn't crash on nullptr. 936 PA_ALWAYS_INLINE constexpr T* GetForExtraction() const { 937 return Impl::SafelyUnwrapPtrForExtraction(wrapped_ptr_); 938 } 939 // This getter is meant *only* for situations where the pointer is meant to be 940 // compared (guaranteeing no dereference or extraction outside of this class). 941 // Any verifications can and should be skipped for performance reasons. 942 PA_ALWAYS_INLINE constexpr T* GetForComparison() const { 943 return Impl::UnsafelyUnwrapPtrForComparison(wrapped_ptr_); 944 } 945 946 PA_ALWAYS_INLINE constexpr T* GetForExtractionAndReset() { 947 T* ptr = GetForExtraction(); 948 operator=(nullptr); 949 return ptr; 950 } 951 952 T* wrapped_ptr_; 953 PA_NO_UNIQUE_ADDRESS internal::InstanceTracer tracer_; 954 955 template <typename U, base::RawPtrTraits R> 956 friend class raw_ptr; 957 }; 958 959 template <typename U, typename V, RawPtrTraits Traits1, RawPtrTraits Traits2> 960 PA_ALWAYS_INLINE constexpr bool operator==(const raw_ptr<U, Traits1>& lhs, 961 const raw_ptr<V, Traits2>& rhs) { 962 return lhs.GetForComparison() == rhs.GetForComparison(); 963 } 964 965 template <typename U, typename V, RawPtrTraits Traits1, RawPtrTraits Traits2> 966 PA_ALWAYS_INLINE constexpr bool operator!=(const raw_ptr<U, Traits1>& lhs, 967 const raw_ptr<V, Traits2>& rhs) { 968 return !(lhs == rhs); 969 } 970 971 template <typename U, typename V, RawPtrTraits Traits1, RawPtrTraits Traits2> 972 PA_ALWAYS_INLINE constexpr bool operator<(const raw_ptr<U, Traits1>& lhs, 973 const raw_ptr<V, Traits2>& rhs) { 974 return lhs.GetForComparison() < rhs.GetForComparison(); 975 } 976 977 template <typename U, typename V, RawPtrTraits Traits1, RawPtrTraits Traits2> 978 PA_ALWAYS_INLINE constexpr bool operator>(const raw_ptr<U, Traits1>& lhs, 979 const raw_ptr<V, Traits2>& rhs) { 980 return lhs.GetForComparison() > rhs.GetForComparison(); 981 } 982 983 template <typename U, typename V, RawPtrTraits Traits1, RawPtrTraits Traits2> 984 PA_ALWAYS_INLINE constexpr bool operator<=(const raw_ptr<U, Traits1>& lhs, 985 const raw_ptr<V, Traits2>& rhs) { 986 return lhs.GetForComparison() <= rhs.GetForComparison(); 987 } 988 989 template <typename U, typename V, RawPtrTraits Traits1, RawPtrTraits Traits2> 990 PA_ALWAYS_INLINE constexpr bool operator>=(const raw_ptr<U, Traits1>& lhs, 991 const raw_ptr<V, Traits2>& rhs) { 992 return lhs.GetForComparison() >= rhs.GetForComparison(); 993 } 994 995 template <typename T> 996 struct IsRawPtr : std::false_type {}; 997 998 template <typename T, RawPtrTraits Traits> 999 struct IsRawPtr<raw_ptr<T, Traits>> : std::true_type {}; 1000 1001 template <typename T> 1002 inline constexpr bool IsRawPtrV = IsRawPtr<T>::value; 1003 1004 template <typename T> 1005 inline constexpr bool IsRawPtrMayDangleV = false; 1006 1007 template <typename T, RawPtrTraits Traits> 1008 inline constexpr bool IsRawPtrMayDangleV<raw_ptr<T, Traits>> = 1009 partition_alloc::internal::ContainsFlags(Traits, RawPtrTraits::kMayDangle); 1010 1011 // Template helpers for working with T* or raw_ptr<T>. 1012 template <typename T> 1013 struct IsRawPointerHelper : std::false_type {}; 1014 1015 template <typename T> 1016 struct IsRawPointerHelper<T*> : std::true_type {}; 1017 1018 template <typename T, RawPtrTraits Traits> 1019 struct IsRawPointerHelper<raw_ptr<T, Traits>> : std::true_type {}; 1020 1021 template <typename T> 1022 inline constexpr bool IsRawPointer = IsRawPointerHelper<T>::value; 1023 1024 template <typename T> 1025 struct RemoveRawPointer { 1026 using type = T; 1027 }; 1028 1029 template <typename T> 1030 struct RemoveRawPointer<T*> { 1031 using type = T; 1032 }; 1033 1034 template <typename T, RawPtrTraits Traits> 1035 struct RemoveRawPointer<raw_ptr<T, Traits>> { 1036 using type = T; 1037 }; 1038 1039 template <typename T> 1040 using RemoveRawPointerT = typename RemoveRawPointer<T>::type; 1041 1042 } // namespace base 1043 1044 using base::raw_ptr; 1045 1046 // DisableDanglingPtrDetection option for raw_ptr annotates 1047 // "intentional-and-safe" dangling pointers. It is meant to be used at the 1048 // margin, only if there is no better way to re-architecture the code. 1049 // 1050 // Usage: 1051 // raw_ptr<T, DisableDanglingPtrDetection> dangling_ptr; 1052 // 1053 // When using it, please provide a justification about what guarantees that it 1054 // will never be dereferenced after becoming dangling. 1055 constexpr inline auto DisableDanglingPtrDetection = 1056 base::RawPtrTraits::kMayDangle; 1057 1058 // See `docs/dangling_ptr.md` 1059 // Annotates known dangling raw_ptr. Those haven't been triaged yet. All the 1060 // occurrences are meant to be removed. See https://crbug.com/1291138. 1061 constexpr inline auto DanglingUntriaged = base::RawPtrTraits::kMayDangle; 1062 1063 // Unlike DanglingUntriaged, this annotates raw_ptrs that are known to 1064 // dangle only occasionally on the CQ. 1065 // 1066 // These were found from CQ runs and analysed in this dashboard: 1067 // https://docs.google.com/spreadsheets/d/1k12PQOG4y1-UEV9xDfP1F8FSk4cVFywafEYHmzFubJ8/ 1068 // 1069 // This is not meant to be added manually. You can ignore this flag. 1070 constexpr inline auto FlakyDanglingUntriaged = base::RawPtrTraits::kMayDangle; 1071 1072 // Dangling raw_ptr that is more likely to cause UAF: its memory was freed in 1073 // one task, and the raw_ptr was released in a different one. 1074 // 1075 // This is not meant to be added manually. You can ignore this flag. 1076 constexpr inline auto AcrossTasksDanglingUntriaged = 1077 base::RawPtrTraits::kMayDangle; 1078 1079 // The use of pointer arithmetic with raw_ptr is strongly discouraged and 1080 // disabled by default. Usually a container like span<> should be used 1081 // instead of the raw_ptr. 1082 constexpr inline auto AllowPtrArithmetic = 1083 base::RawPtrTraits::kAllowPtrArithmetic; 1084 1085 // The use of uninitialized pointers is strongly discouraged. raw_ptrs will 1086 // be initialized to nullptr by default in all cases when building against 1087 // Chromium. However, third-party projects built in a standalone manner may 1088 // wish to opt out where possible. One way to do this is via buildflags, 1089 // thus affecting all raw_ptrs, but a finer-grained mechanism is the use 1090 // of the kAllowUninitialized trait. 1091 // 1092 // Note that opting out may not always be effective, given that algorithms 1093 // like BackupRefPtr require nullptr initializaion for correctness and thus 1094 // silently enforce it. 1095 constexpr inline auto AllowUninitialized = 1096 base::RawPtrTraits::kAllowUninitialized; 1097 1098 // This flag is used to tag a subset of dangling pointers. Similarly to 1099 // DanglingUntriaged, those pointers are known to be dangling. However, we also 1100 // detected that those raw_ptr's were never released (either by calling 1101 // raw_ptr's destructor or by resetting its value), which can ultimately put 1102 // pressure on the BRP quarantine. 1103 // 1104 // This is not meant to be added manually. You can ignore this flag. 1105 constexpr inline auto LeakedDanglingUntriaged = base::RawPtrTraits::kMayDangle; 1106 1107 // Temporary introduced alias in the context of rewriting std::vector<T*> into 1108 // std::vector<raw_ptr<T>> and in order to temporarily bypass the dangling ptr 1109 // checks on the CQ. This alias will be removed gradually after the cl lands and 1110 // will be replaced by DanglingUntriaged where necessary. 1111 constexpr inline auto VectorExperimental = base::RawPtrTraits::kMayDangle; 1112 1113 // Temporary alias introduced in the context of rewriting std::set<T*> into 1114 // std::set<raw_ptr<T>> and in order to temporarily bypass the dangling ptr 1115 // checks on the CQ. This alias will be removed gradually after the rewrite cl 1116 // lands and will be replaced by DanglingUntriaged where necessary. 1117 constexpr inline auto SetExperimental = base::RawPtrTraits::kMayDangle; 1118 1119 // Temporary alias introduced in the context of rewriting more containers and in 1120 // order to temporarily bypass the dangling ptr checks on the CQ. This alias 1121 // will be removed gradually after the rewrite cl lands and will be replaced by 1122 // DanglingUntriaged where necessary. 1123 constexpr inline auto CtnExperimental = base::RawPtrTraits::kMayDangle; 1124 1125 // Public verson used in callbacks arguments when it is known that they might 1126 // receive dangling pointers. In any other cases, please 1127 // use one of: 1128 // - raw_ptr<T, DanglingUntriaged> 1129 // - raw_ptr<T, DisableDanglingPtrDetection> 1130 template <typename T, base::RawPtrTraits Traits = base::RawPtrTraits::kEmpty> 1131 using MayBeDangling = base::raw_ptr<T, Traits | base::RawPtrTraits::kMayDangle>; 1132 1133 namespace std { 1134 1135 // Override so set/map lookups do not create extra raw_ptr. This also allows 1136 // dangling pointers to be used for lookup. 1137 template <typename T, base::RawPtrTraits Traits> 1138 struct less<raw_ptr<T, Traits>> { 1139 using Impl = typename raw_ptr<T, Traits>::Impl; 1140 using is_transparent = void; 1141 1142 bool operator()(const raw_ptr<T, Traits>& lhs, 1143 const raw_ptr<T, Traits>& rhs) const { 1144 Impl::IncrementLessCountForTest(); 1145 return lhs < rhs; 1146 } 1147 1148 bool operator()(T* lhs, const raw_ptr<T, Traits>& rhs) const { 1149 Impl::IncrementLessCountForTest(); 1150 return lhs < rhs; 1151 } 1152 1153 bool operator()(const raw_ptr<T, Traits>& lhs, T* rhs) const { 1154 Impl::IncrementLessCountForTest(); 1155 return lhs < rhs; 1156 } 1157 }; 1158 1159 template <typename T, base::RawPtrTraits Traits> 1160 struct hash<raw_ptr<T, Traits>> { 1161 typedef raw_ptr<T, Traits> argument_type; 1162 typedef std::size_t result_type; 1163 result_type operator()(argument_type const& ptr) const { 1164 return hash<T*>()(ptr.get()); 1165 } 1166 }; 1167 1168 // Define for cases where raw_ptr<T> holds a pointer to an array of type T. 1169 // This is consistent with definition of std::iterator_traits<T*>. 1170 // Algorithms like std::binary_search need that. 1171 template <typename T, base::RawPtrTraits Traits> 1172 struct iterator_traits<raw_ptr<T, Traits>> { 1173 using difference_type = ptrdiff_t; 1174 using value_type = std::remove_cv_t<T>; 1175 using pointer = T*; 1176 using reference = T&; 1177 using iterator_category = std::random_access_iterator_tag; 1178 }; 1179 1180 // Specialize std::pointer_traits. The latter is required to obtain the 1181 // underlying raw pointer in the std::to_address(pointer) overload. 1182 // Implementing the pointer_traits is the standard blessed way to customize 1183 // `std::to_address(pointer)` in C++20 [3]. 1184 // 1185 // [1] https://wg21.link/pointer.traits.optmem 1186 1187 template <typename T, ::base::RawPtrTraits Traits> 1188 struct pointer_traits<::raw_ptr<T, Traits>> { 1189 using pointer = ::raw_ptr<T, Traits>; 1190 using element_type = T; 1191 using difference_type = ptrdiff_t; 1192 1193 template <typename U> 1194 using rebind = ::raw_ptr<U, Traits>; 1195 1196 static constexpr pointer pointer_to(element_type& r) noexcept { 1197 return pointer(&r); 1198 } 1199 1200 static constexpr element_type* to_address(pointer p) noexcept { 1201 return p.get(); 1202 } 1203 }; 1204 1205 } // namespace std 1206 1207 #endif // PARTITION_ALLOC_POINTERS_RAW_PTR_H_ 1208