blob: ea52bc20efab2f128231a134ea5fd50794811cca [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "partition_alloc/pointers/raw_ptr_backup_ref_impl.h"
#include <cstdint>
#include "partition_alloc/dangling_raw_ptr_checks.h"
#include "partition_alloc/partition_alloc.h"
#include "partition_alloc/partition_alloc_base/check.h"
#include "partition_alloc/partition_alloc_buildflags.h"
#include "partition_alloc/partition_ref_count.h"
#include "partition_alloc/partition_root.h"
#include "partition_alloc/reservation_offset_table.h"
namespace base::internal {
template <bool AllowDangling, bool ExperimentalAsh>
void RawPtrBackupRefImpl<AllowDangling, ExperimentalAsh>::AcquireInternal(
uintptr_t address) {
#if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
PA_BASE_CHECK(UseBrp(address));
#endif
uintptr_t slot_start =
partition_alloc::PartitionAllocGetSlotStartInBRPPool(address);
if constexpr (AllowDangling) {
partition_alloc::internal::PartitionRefCountPointer(slot_start)
->AcquireFromUnprotectedPtr();
} else {
partition_alloc::internal::PartitionRefCountPointer(slot_start)->Acquire();
}
}
template <bool AllowDangling, bool ExperimentalAsh>
void RawPtrBackupRefImpl<AllowDangling, ExperimentalAsh>::ReleaseInternal(
uintptr_t address) {
#if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
PA_BASE_CHECK(UseBrp(address));
#endif
uintptr_t slot_start =
partition_alloc::PartitionAllocGetSlotStartInBRPPool(address);
if constexpr (AllowDangling) {
if (partition_alloc::internal::PartitionRefCountPointer(slot_start)
->ReleaseFromUnprotectedPtr()) {
partition_alloc::internal::PartitionAllocFreeForRefCounting(slot_start);
}
} else {
if (partition_alloc::internal::PartitionRefCountPointer(slot_start)
->Release()) {
partition_alloc::internal::PartitionAllocFreeForRefCounting(slot_start);
}
}
}
template <bool AllowDangling, bool ExperimentalAsh>
void RawPtrBackupRefImpl<AllowDangling, ExperimentalAsh>::
ReportIfDanglingInternal(uintptr_t address) {
if (partition_alloc::internal::IsUnretainedDanglingRawPtrCheckEnabled()) {
if (IsSupportedAndNotNull(address)) {
uintptr_t slot_start =
partition_alloc::PartitionAllocGetSlotStartInBRPPool(address);
partition_alloc::internal::PartitionRefCountPointer(slot_start)
->ReportIfDangling();
}
}
}
// static
template <bool AllowDangling, bool ExperimentalAsh>
bool RawPtrBackupRefImpl<AllowDangling, ExperimentalAsh>::
CheckPointerWithinSameAlloc(uintptr_t before_addr,
uintptr_t after_addr,
size_t type_size) {
partition_alloc::internal::PtrPosWithinAlloc ptr_pos_within_alloc =
partition_alloc::internal::IsPtrWithinSameAlloc(before_addr, after_addr,
type_size);
// No need to check that |new_ptr| is in the same pool, as
// IsPtrWithinSameAlloc() checks that it's within the same allocation, so
// must be the same pool.
PA_BASE_CHECK(ptr_pos_within_alloc !=
partition_alloc::internal::PtrPosWithinAlloc::kFarOOB);
#if BUILDFLAG(BACKUP_REF_PTR_POISON_OOB_PTR)
return ptr_pos_within_alloc ==
partition_alloc::internal::PtrPosWithinAlloc::kAllocEnd;
#else
return false;
#endif
}
template <bool AllowDangling, bool ExperimentalAsh>
bool RawPtrBackupRefImpl<AllowDangling, ExperimentalAsh>::IsPointeeAlive(
uintptr_t address) {
#if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
PA_BASE_CHECK(UseBrp(address));
#endif
uintptr_t slot_start =
partition_alloc::PartitionAllocGetSlotStartInBRPPool(address);
return partition_alloc::internal::PartitionRefCountPointer(slot_start)
->IsAlive();
}
// Explicitly instantiates the two BackupRefPtr variants in the .cc. This
// ensures the definitions not visible from the .h are available in the binary.
template struct RawPtrBackupRefImpl</*AllowDangling=*/false,
/*ExperimentalAsh=*/false>;
template struct RawPtrBackupRefImpl</*AllowDangling=*/false,
/*ExperimentalAsh=*/true>;
template struct RawPtrBackupRefImpl</*AllowDangling=*/true,
/*ExperimentalAsh=*/false>;
template struct RawPtrBackupRefImpl</*AllowDangling=*/true,
/*ExperimentalAsh=*/true>;
#if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
void CheckThatAddressIsntWithinFirstPartitionPage(uintptr_t address) {
if (partition_alloc::internal::IsManagedByDirectMap(address)) {
uintptr_t reservation_start =
partition_alloc::internal::GetDirectMapReservationStart(address);
PA_BASE_CHECK(address - reservation_start >=
partition_alloc::PartitionPageSize());
} else {
PA_BASE_CHECK(partition_alloc::internal::IsManagedByNormalBuckets(address));
PA_BASE_CHECK(address % partition_alloc::kSuperPageSize >=
partition_alloc::PartitionPageSize());
}
}
#endif // BUILDFLAG(PA_DCHECK_IS_ON) ||
// BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
} // namespace base::internal