xref: /aosp_15_r20/external/cronet/base/test/memory/dangling_ptr_instrumentation.h (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 
5 #ifndef BASE_TEST_MEMORY_DANGLING_PTR_INSTRUMENTATION_H_
6 #define BASE_TEST_MEMORY_DANGLING_PTR_INSTRUMENTATION_H_
7 
8 #include <cstdint>
9 #include <string_view>
10 
11 #include "base/memory/raw_ptr.h"
12 #include "base/types/expected.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 // It is difficult to configure malloc as partition_alloc in death test and
19 // enable BackupRefPtr. This can be used as an alternative. This replaces a
20 // crash by incrementing a set of counters.
21 //
22 // Usage:
23 //
24 // ```cpp
25 // TEST(DanglingTest, Basic) {
26 //   auto instrumentation = test::DanglingPtrInstrumentation::Create();
27 //   if (!instrumentation.has_value()) {
28 //     GTEST_SKIP() << instrumentation.error();
29 //   }
30 //
31 //   [...]
32 //   EXPECT_EQ(instrumentation->dangling_ptr_detected(), 0u);
33 //   EXPECT_EQ(instrumentation->dangling_ptr_released(), 0u);
34 // }
35 // ```
36 class DanglingPtrInstrumentation {
37  public:
38   // Returns the DanglingPtrInstrumentation or a reason why it can't be used,
39   // in which case the test should be skipped.
40   //
41   // This function should typically be called from the `testing::Test::SetUp()`
42   // override so that it can skip the test with `GTEST_SKIP()` on failure.
43   static base::expected<DanglingPtrInstrumentation, std::string_view> Create();
44 
45   ~DanglingPtrInstrumentation();
46   DanglingPtrInstrumentation(const DanglingPtrInstrumentation&) = delete;
47   DanglingPtrInstrumentation(DanglingPtrInstrumentation&&);
48   DanglingPtrInstrumentation& operator=(const DanglingPtrInstrumentation&) =
49       delete;
50   DanglingPtrInstrumentation& operator=(DanglingPtrInstrumentation&&);
51 
dangling_ptr_detected()52   size_t dangling_ptr_detected() { return dangling_ptr_detected_; }
dangling_ptr_released()53   size_t dangling_ptr_released() { return dangling_ptr_released_; }
54 
55  private:
56   static void IncreaseCountDetected(std::uintptr_t);
57   static void IncreaseCountReleased(std::uintptr_t);
58   static raw_ptr<DanglingPtrInstrumentation> g_observer;
59 
60   DanglingPtrInstrumentation();
61 
62   void Register();
63   void Unregister();
64 
65   size_t dangling_ptr_detected_ = 0;
66   size_t dangling_ptr_released_ = 0;
67   partition_alloc::DanglingRawPtrDetectedFn* old_detected_fn_ = nullptr;
68   partition_alloc::DanglingRawPtrReleasedFn* old_dereferenced_fn_ = nullptr;
69 };
70 
71 }  // namespace base::test
72 
73 #endif  // BASE_TEST_MEMORY_DANGLING_PTR_INSTRUMENTATION_H_
74