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)20void 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)35void 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)55void 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)69bool 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)91bool 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)107void 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