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 #include "base/test/memory/dangling_ptr_instrumentation.h" 5 6 #include <cstdint> 7 #include <string_view> 8 9 #include "base/allocator/partition_alloc_features.h" 10 #include "base/check_op.h" 11 #include "base/feature_list.h" 12 #include "base/memory/raw_ptr.h" 13 #include "partition_alloc/dangling_raw_ptr_checks.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 16 namespace base::test { 17 18 // static 19 base::expected<DanglingPtrInstrumentation, std::string_view> Create()20DanglingPtrInstrumentation::Create() { 21 if (!FeatureList::IsEnabled(features::kPartitionAllocBackupRefPtr)) { 22 return base::unexpected( 23 "DanglingPtrInstrumentation requires the feature flag " 24 "'PartitionAllocBackupRefPtr' to be on."); 25 } 26 // Note: We don't need to enable the `PartitionAllocDanglingPtr` feature, 27 // because this does provide an alternative "implementation", by incrementing 28 // the two counters. 29 30 #if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) 31 return base::unexpected( 32 "DanglingPtrInstrumentation requires the binary flag " 33 "'use_partition_alloc_as_malloc' to be on."); 34 #elif !BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS) 35 return base::unexpected( 36 "DanglingPtrInstrumentation requires the binary flag " 37 "'enable_dangling_raw_ptr_checks' to be on."); 38 #else 39 return DanglingPtrInstrumentation(); 40 #endif 41 } 42 DanglingPtrInstrumentation()43DanglingPtrInstrumentation::DanglingPtrInstrumentation() { 44 Register(); 45 } 46 ~DanglingPtrInstrumentation()47DanglingPtrInstrumentation::~DanglingPtrInstrumentation() { 48 Unregister(); 49 } 50 DanglingPtrInstrumentation(DanglingPtrInstrumentation && old)51DanglingPtrInstrumentation::DanglingPtrInstrumentation( 52 DanglingPtrInstrumentation&& old) { 53 operator=(std::move(old)); 54 } 55 operator =(DanglingPtrInstrumentation && old)56DanglingPtrInstrumentation& DanglingPtrInstrumentation::operator=( 57 DanglingPtrInstrumentation&& old) { 58 old.Unregister(); 59 Register(); 60 return *this; 61 } 62 Register()63void DanglingPtrInstrumentation::Register() { 64 CHECK_EQ(g_observer, nullptr); 65 g_observer = this; 66 old_detected_fn_ = partition_alloc::GetDanglingRawPtrDetectedFn(); 67 old_dereferenced_fn_ = partition_alloc::GetDanglingRawPtrReleasedFn(); 68 partition_alloc::SetDanglingRawPtrDetectedFn(IncreaseCountDetected); 69 partition_alloc::SetDanglingRawPtrReleasedFn(IncreaseCountReleased); 70 } 71 Unregister()72void DanglingPtrInstrumentation::Unregister() { 73 if (g_observer != this) { 74 return; 75 } 76 g_observer = nullptr; 77 partition_alloc::SetDanglingRawPtrDetectedFn(old_detected_fn_); 78 partition_alloc::SetDanglingRawPtrReleasedFn(old_dereferenced_fn_); 79 } 80 81 raw_ptr<DanglingPtrInstrumentation> DanglingPtrInstrumentation::g_observer = 82 nullptr; 83 84 // static IncreaseCountDetected(std::uintptr_t)85void DanglingPtrInstrumentation::IncreaseCountDetected(std::uintptr_t) { 86 g_observer->dangling_ptr_detected_++; 87 } 88 89 // static IncreaseCountReleased(std::uintptr_t)90void DanglingPtrInstrumentation::IncreaseCountReleased(std::uintptr_t) { 91 g_observer->dangling_ptr_released_++; 92 } 93 94 } // namespace base::test 95