// Copyright (c) 2021 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/memory/nonscannable_memory.h" #include #include "base/allocator/buildflags.h" #include "base/feature_list.h" #include "base/no_destructor.h" #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) #include "base/allocator/allocator_shim_default_dispatch_to_partition_alloc.h" #include "base/allocator/partition_alloc_features.h" #include "base/allocator/partition_allocator/starscan/pcscan.h" #endif namespace base { namespace internal { #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) template NonScannableAllocatorImpl::NonScannableAllocatorImpl() = default; template NonScannableAllocatorImpl::~NonScannableAllocatorImpl() = default; template NonScannableAllocatorImpl& NonScannableAllocatorImpl::Instance() { static base::NoDestructor instance; return *instance; } template void* NonScannableAllocatorImpl::Alloc(size_t size) { // TODO(bikineev): Change to LIKELY once PCScan is enabled by default. if (UNLIKELY(pcscan_enabled_.load(std::memory_order_acquire))) { PA_DCHECK(allocator_.get()); return allocator_->root()->AllocWithFlagsNoHooks( 0, size, partition_alloc::PartitionPageSize()); } // Otherwise, dispatch to default partition. return PartitionAllocMalloc::Allocator()->AllocWithFlagsNoHooks( 0, size, partition_alloc::PartitionPageSize()); } template void NonScannableAllocatorImpl::Free(void* ptr) { partition_alloc::ThreadSafePartitionRoot::FreeNoHooks(ptr); } template void NonScannableAllocatorImpl::NotifyPCScanEnabled() { allocator_.reset(partition_alloc::internal::MakePCScanMetadata< partition_alloc::PartitionAllocator>()); allocator_->init({ partition_alloc::PartitionOptions::AlignedAlloc::kDisallowed, partition_alloc::PartitionOptions::ThreadCache::kDisabled, Quarantinable ? partition_alloc::PartitionOptions::Quarantine::kAllowed : partition_alloc::PartitionOptions::Quarantine::kDisallowed, partition_alloc::PartitionOptions::Cookie::kAllowed, partition_alloc::PartitionOptions::BackupRefPtr::kDisabled, partition_alloc::PartitionOptions::BackupRefPtrZapping::kDisabled, partition_alloc::PartitionOptions::UseConfigurablePool::kNo, }); if (Quarantinable) partition_alloc::internal::PCScan::RegisterNonScannableRoot( allocator_->root()); pcscan_enabled_.store(true, std::memory_order_release); } template class NonScannableAllocatorImpl; template class NonScannableAllocatorImpl; #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) } // namespace internal void* AllocNonScannable(size_t size) { #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) return internal::NonScannableAllocatorImpl::Instance() .Alloc(size); #else return ::malloc(size); #endif } void FreeNonScannable(void* ptr) { #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) internal::NonScannableAllocatorImpl::Free(ptr); #else return ::free(ptr); #endif } void* AllocNonQuarantinable(size_t size) { #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) return internal::NonScannableAllocatorImpl< /*Quarantinable=*/false>::Instance() .Alloc(size); #else return ::malloc(size); #endif } void FreeNonQuarantinable(void* ptr) { #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) internal::NonScannableAllocatorImpl::Free(ptr); #else return ::free(ptr); #endif } } // namespace base