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