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