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