• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()19 DanglingPtrInstrumentation::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()46 DanglingPtrInstrumentation::DanglingPtrInstrumentation() {
47   Register();
48 }
49 
~DanglingPtrInstrumentation()50 DanglingPtrInstrumentation::~DanglingPtrInstrumentation() {
51   Unregister();
52 }
53 
DanglingPtrInstrumentation(DanglingPtrInstrumentation && old)54 DanglingPtrInstrumentation::DanglingPtrInstrumentation(
55     DanglingPtrInstrumentation&& old) {
56   operator=(std::move(old));
57 }
58 
operator =(DanglingPtrInstrumentation && old)59 DanglingPtrInstrumentation& DanglingPtrInstrumentation::operator=(
60     DanglingPtrInstrumentation&& old) {
61   old.Unregister();
62   Register();
63   return *this;
64 }
65 
Register()66 void 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()75 void 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)88 void DanglingPtrInstrumentation::IncreaseCountDetected(std::uintptr_t) {
89   g_observer->dangling_ptr_detected_++;
90 }
91 
92 // static
IncreaseCountReleased(std::uintptr_t)93 void DanglingPtrInstrumentation::IncreaseCountReleased(std::uintptr_t) {
94   g_observer->dangling_ptr_released_++;
95 }
96 
97 }  // namespace base::test
98