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