• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 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 #include "base/allocator/partition_allocator/pointers/raw_ptr_backup_ref_impl.h"
6 
7 #include <cstdint>
8 
9 #include "base/allocator/partition_allocator/dangling_raw_ptr_checks.h"
10 #include "base/allocator/partition_allocator/partition_alloc.h"
11 #include "base/allocator/partition_allocator/partition_alloc_base/check.h"
12 #include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
13 #include "base/allocator/partition_allocator/partition_ref_count.h"
14 #include "base/allocator/partition_allocator/partition_root.h"
15 #include "base/allocator/partition_allocator/reservation_offset_table.h"
16 
17 namespace base::internal {
18 
19 template <bool AllowDangling>
AcquireInternal(uintptr_t address)20 void RawPtrBackupRefImpl<AllowDangling>::AcquireInternal(uintptr_t address) {
21 #if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
22   PA_BASE_CHECK(partition_alloc::IsManagedByPartitionAllocBRPPool(address));
23 #endif
24   uintptr_t slot_start =
25       partition_alloc::PartitionAllocGetSlotStartInBRPPool(address);
26   if constexpr (AllowDangling) {
27     partition_alloc::internal::PartitionRefCountPointer(slot_start)
28         ->AcquireFromUnprotectedPtr();
29   } else {
30     partition_alloc::internal::PartitionRefCountPointer(slot_start)->Acquire();
31   }
32 }
33 
34 template <bool AllowDangling>
ReleaseInternal(uintptr_t address)35 void RawPtrBackupRefImpl<AllowDangling>::ReleaseInternal(uintptr_t address) {
36 #if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
37   PA_BASE_CHECK(partition_alloc::IsManagedByPartitionAllocBRPPool(address));
38 #endif
39   uintptr_t slot_start =
40       partition_alloc::PartitionAllocGetSlotStartInBRPPool(address);
41   if constexpr (AllowDangling) {
42     if (partition_alloc::internal::PartitionRefCountPointer(slot_start)
43             ->ReleaseFromUnprotectedPtr()) {
44       partition_alloc::internal::PartitionAllocFreeForRefCounting(slot_start);
45     }
46   } else {
47     if (partition_alloc::internal::PartitionRefCountPointer(slot_start)
48             ->Release()) {
49       partition_alloc::internal::PartitionAllocFreeForRefCounting(slot_start);
50     }
51   }
52 }
53 
54 template <bool AllowDangling>
ReportIfDanglingInternal(uintptr_t address)55 void RawPtrBackupRefImpl<AllowDangling>::ReportIfDanglingInternal(
56     uintptr_t address) {
57   if (partition_alloc::internal::IsUnretainedDanglingRawPtrCheckEnabled()) {
58     if (IsSupportedAndNotNull(address)) {
59       uintptr_t slot_start =
60           partition_alloc::PartitionAllocGetSlotStartInBRPPool(address);
61       partition_alloc::internal::PartitionRefCountPointer(slot_start)
62           ->ReportIfDangling();
63     }
64   }
65 }
66 
67 // static
68 template <bool AllowDangling>
CheckPointerWithinSameAlloc(uintptr_t before_addr,uintptr_t after_addr,size_t type_size)69 bool RawPtrBackupRefImpl<AllowDangling>::CheckPointerWithinSameAlloc(
70     uintptr_t before_addr,
71     uintptr_t after_addr,
72     size_t type_size) {
73   partition_alloc::internal::PtrPosWithinAlloc ptr_pos_within_alloc =
74       partition_alloc::internal::IsPtrWithinSameAlloc(before_addr, after_addr,
75                                                       type_size);
76   // No need to check that |new_ptr| is in the same pool, as
77   // IsPtrWithinSameAlloc() checks that it's within the same allocation, so
78   // must be the same pool.
79   PA_BASE_CHECK(ptr_pos_within_alloc !=
80                 partition_alloc::internal::PtrPosWithinAlloc::kFarOOB);
81 
82 #if BUILDFLAG(BACKUP_REF_PTR_POISON_OOB_PTR)
83   return ptr_pos_within_alloc ==
84          partition_alloc::internal::PtrPosWithinAlloc::kAllocEnd;
85 #else
86   return false;
87 #endif
88 }
89 
90 template <bool AllowDangling>
IsPointeeAlive(uintptr_t address)91 bool RawPtrBackupRefImpl<AllowDangling>::IsPointeeAlive(uintptr_t address) {
92 #if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
93   PA_BASE_CHECK(partition_alloc::IsManagedByPartitionAllocBRPPool(address));
94 #endif
95   uintptr_t slot_start =
96       partition_alloc::PartitionAllocGetSlotStartInBRPPool(address);
97   return partition_alloc::internal::PartitionRefCountPointer(slot_start)
98       ->IsAlive();
99 }
100 
101 // Explicitly instantiates the two BackupRefPtr variants in the .cc. This
102 // ensures the definitions not visible from the .h are available in the binary.
103 template struct RawPtrBackupRefImpl</*AllowDangling=*/false>;
104 template struct RawPtrBackupRefImpl</*AllowDangling=*/true>;
105 
106 #if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
CheckThatAddressIsntWithinFirstPartitionPage(uintptr_t address)107 void CheckThatAddressIsntWithinFirstPartitionPage(uintptr_t address) {
108   if (partition_alloc::internal::IsManagedByDirectMap(address)) {
109     uintptr_t reservation_start =
110         partition_alloc::internal::GetDirectMapReservationStart(address);
111     PA_BASE_CHECK(address - reservation_start >=
112                   partition_alloc::PartitionPageSize());
113   } else {
114     PA_BASE_CHECK(partition_alloc::internal::IsManagedByNormalBuckets(address));
115     PA_BASE_CHECK(address % partition_alloc::kSuperPageSize >=
116                   partition_alloc::PartitionPageSize());
117   }
118 }
119 #endif  // BUILDFLAG(PA_DCHECK_IS_ON) ||
120         // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
121 
122 }  // namespace base::internal
123