xref: /aosp_15_r20/external/cronet/base/test/memory/dangling_ptr_instrumentation.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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()20 DanglingPtrInstrumentation::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()43 DanglingPtrInstrumentation::DanglingPtrInstrumentation() {
44   Register();
45 }
46 
~DanglingPtrInstrumentation()47 DanglingPtrInstrumentation::~DanglingPtrInstrumentation() {
48   Unregister();
49 }
50 
DanglingPtrInstrumentation(DanglingPtrInstrumentation && old)51 DanglingPtrInstrumentation::DanglingPtrInstrumentation(
52     DanglingPtrInstrumentation&& old) {
53   operator=(std::move(old));
54 }
55 
operator =(DanglingPtrInstrumentation && old)56 DanglingPtrInstrumentation& DanglingPtrInstrumentation::operator=(
57     DanglingPtrInstrumentation&& old) {
58   old.Unregister();
59   Register();
60   return *this;
61 }
62 
Register()63 void 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()72 void 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)85 void DanglingPtrInstrumentation::IncreaseCountDetected(std::uintptr_t) {
86   g_observer->dangling_ptr_detected_++;
87 }
88 
89 // static
IncreaseCountReleased(std::uintptr_t)90 void DanglingPtrInstrumentation::IncreaseCountReleased(std::uintptr_t) {
91   g_observer->dangling_ptr_released_++;
92 }
93 
94 }  // namespace base::test
95