1 // Copyright 2024 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 PARTITION_ALLOC_POINTERS_INSTANCE_TRACER_H_
6 #define PARTITION_ALLOC_POINTERS_INSTANCE_TRACER_H_
7 
8 #include <array>
9 #include <atomic>
10 #include <cstdint>
11 #include <utility>
12 #include <vector>
13 
14 #include "partition_alloc/partition_alloc_base/compiler_specific.h"
15 #include "partition_alloc/partition_alloc_base/component_export.h"
16 #include "partition_alloc/partition_alloc_base/cxx20_is_constant_evaluated.h"
17 #include "partition_alloc/partition_alloc_buildflags.h"
18 
19 namespace base::internal {
20 
21 #if !BUILDFLAG(ENABLE_BACKUP_REF_PTR_INSTANCE_TRACER)
22 
23 // When the buildflag is disabled, use a minimal no-state implementation so
24 // sizeof(raw_ptr<T>) == sizeof(T*).
25 class InstanceTracer {
26  public:
owner_id()27   constexpr uint64_t owner_id() const { return 0; }
28 
Trace(uint64_t owner_id,uintptr_t address)29   constexpr static void Trace([[maybe_unused]] uint64_t owner_id,
30                               [[maybe_unused]] uintptr_t address) {}
Untrace(uint64_t owner_id)31   constexpr static void Untrace([[maybe_unused]] uint64_t owner_id) {}
32 };
33 
34 #else
35 
36 class PA_TRIVIAL_ABI InstanceTracer {
37  public:
38   constexpr InstanceTracer() : owner_id_(CreateOwnerId()) {}
39 
40   // Copy constructing InstanceTracer should not inherit the owner ID; the new
41   // InstanceTracer needs a new ID to be separately tracked.
42   constexpr InstanceTracer(const InstanceTracer&) : InstanceTracer() {}
43   // Similarly, copy assigning an InstanceTracer should not take the owner ID
44   // from the right-hand side; it should preserve the owner ID.
45   constexpr InstanceTracer& operator=(const InstanceTracer&) { return *this; }
46 
47   constexpr InstanceTracer(InstanceTracer&&) : InstanceTracer() {}
48   constexpr InstanceTracer& operator=(InstanceTracer&&) { return *this; }
49 
50   constexpr uint64_t owner_id() const { return owner_id_; }
51 
52   constexpr static void Trace(uint64_t owner_id,
53                               bool may_dangle,
54                               uintptr_t address) {
55     if (partition_alloc::internal::base::is_constant_evaluated() ||
56         owner_id == 0) {
57       return;
58     }
59     TraceImpl(owner_id, may_dangle, address);
60   }
61   constexpr static void Untrace(uint64_t owner_id) {
62     if (partition_alloc::internal::base::is_constant_evaluated() ||
63         owner_id == 0) {
64       return;
65     }
66     UntraceImpl(owner_id);
67   }
68 
69   PA_COMPONENT_EXPORT(RAW_PTR)
70   static std::vector<std::array<const void*, 32>> GetStackTracesForDanglingRefs(
71       uintptr_t allocation);
72 
73   PA_COMPONENT_EXPORT(RAW_PTR)
74   static std::vector<std::array<const void*, 32>>
75   GetStackTracesForAddressForTest(const void* address);
76 
77  private:
78   PA_COMPONENT_EXPORT(RAW_PTR)
79   static void TraceImpl(uint64_t owner_id, bool may_dangle, uintptr_t address);
80   PA_COMPONENT_EXPORT(RAW_PTR) static void UntraceImpl(uint64_t owner_id);
81 
82   constexpr uint64_t CreateOwnerId() {
83     if (partition_alloc::internal::base::is_constant_evaluated()) {
84       return 0;
85     }
86     return ++counter_;
87   }
88 
89   PA_COMPONENT_EXPORT(RAW_PTR) static std::atomic<uint64_t> counter_;
90 
91   // 0 is treated as 'ownerless'. It is used as a sentinel for constexpr
92   // raw_ptrs or other places where owner tracking doesn't make sense.
93   uint64_t owner_id_ = 0;
94 };
95 
96 #endif
97 
98 }  // namespace base::internal
99 
100 #endif  // PARTITION_ALLOC_POINTERS_INSTANCE_TRACER_H_
101