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 PARTITION_ALLOC_POINTERS_RAW_PTR_ASAN_UNOWNED_IMPL_H_ 6 #define PARTITION_ALLOC_POINTERS_RAW_PTR_ASAN_UNOWNED_IMPL_H_ 7 8 #include <cstddef> 9 #include <type_traits> 10 11 #include "partition_alloc/partition_alloc_base/compiler_specific.h" 12 #include "partition_alloc/partition_alloc_base/cxx20_is_constant_evaluated.h" 13 #include "partition_alloc/partition_alloc_buildflags.h" 14 #include "partition_alloc/partition_alloc_forward.h" 15 16 #if !BUILDFLAG(USE_ASAN_UNOWNED_PTR) 17 #error "Included under wrong build option" 18 #endif 19 20 namespace base::internal { 21 22 bool EndOfAliveAllocation(const volatile void* ptr, bool is_adjustable_ptr); 23 bool LikelySmuggledScalar(const volatile void* ptr); 24 25 template <bool IsAdjustablePtr, bool MayDangle> 26 struct RawPtrAsanUnownedImpl { 27 // The first two are needed for correctness. The last one isn't technically a 28 // must, but better to set it. 29 static constexpr bool kMustZeroOnConstruct = true; 30 static constexpr bool kMustZeroOnMove = true; 31 static constexpr bool kMustZeroOnDestruct = true; 32 33 // Wraps a pointer. 34 template <typename T> WrapRawPtrRawPtrAsanUnownedImpl35 PA_ALWAYS_INLINE static constexpr T* WrapRawPtr(T* ptr) { 36 return ptr; 37 } 38 39 // Notifies the allocator when a wrapped pointer is being removed or replaced. 40 template <typename T> ReleaseWrappedPtrRawPtrAsanUnownedImpl41 PA_ALWAYS_INLINE static constexpr void ReleaseWrappedPtr(T* wrapped_ptr) { 42 if (!partition_alloc::internal::base::is_constant_evaluated()) { 43 ProbeForLowSeverityLifetimeIssue(wrapped_ptr); 44 } 45 } 46 47 // Unwraps the pointer, while asserting that memory hasn't been freed. The 48 // function is allowed to crash on nullptr. 49 template <typename T> SafelyUnwrapPtrForDereferenceRawPtrAsanUnownedImpl50 PA_ALWAYS_INLINE static constexpr T* SafelyUnwrapPtrForDereference( 51 T* wrapped_ptr) { 52 // ASAN will catch use of dereferenced ptr without additional probing. 53 return wrapped_ptr; 54 } 55 56 // Unwraps the pointer, while asserting that memory hasn't been freed. The 57 // function must handle nullptr gracefully. 58 template <typename T> SafelyUnwrapPtrForExtractionRawPtrAsanUnownedImpl59 PA_ALWAYS_INLINE static constexpr T* SafelyUnwrapPtrForExtraction( 60 T* wrapped_ptr) { 61 if (!partition_alloc::internal::base::is_constant_evaluated()) { 62 ProbeForLowSeverityLifetimeIssue(wrapped_ptr); 63 } 64 return wrapped_ptr; 65 } 66 67 // Unwraps the pointer, without making an assertion on whether memory was 68 // freed or not. 69 template <typename T> UnsafelyUnwrapPtrForComparisonRawPtrAsanUnownedImpl70 PA_ALWAYS_INLINE static constexpr T* UnsafelyUnwrapPtrForComparison( 71 T* wrapped_ptr) { 72 return wrapped_ptr; 73 } 74 75 // Upcasts the wrapped pointer. 76 template <typename To, typename From> UpcastRawPtrAsanUnownedImpl77 PA_ALWAYS_INLINE static constexpr To* Upcast(From* wrapped_ptr) { 78 static_assert(std::is_convertible_v<From*, To*>, 79 "From must be convertible to To."); 80 // Note, this cast may change the address if upcasting to base that lies in 81 // the middle of the derived object. 82 return wrapped_ptr; 83 } 84 85 // Advance the wrapped pointer by `delta_elems`. 86 template < 87 typename T, 88 typename Z, 89 typename = 90 std::enable_if_t<partition_alloc::internal::is_offset_type<Z>, void>> 91 PA_ALWAYS_INLINE static constexpr T* AdvanceRawPtrAsanUnownedImpl92 Advance(T* wrapped_ptr, Z delta_elems, bool /*is_in_pointer_modification*/) { 93 return wrapped_ptr + delta_elems; 94 } 95 96 // Retreat the wrapped pointer by `delta_elems`. 97 template < 98 typename T, 99 typename Z, 100 typename = 101 std::enable_if_t<partition_alloc::internal::is_offset_type<Z>, void>> 102 PA_ALWAYS_INLINE static constexpr T* RetreatRawPtrAsanUnownedImpl103 Retreat(T* wrapped_ptr, Z delta_elems, bool /*is_in_pointer_modification*/) { 104 return wrapped_ptr - delta_elems; 105 } 106 107 template <typename T> GetDeltaElemsRawPtrAsanUnownedImpl108 PA_ALWAYS_INLINE static constexpr ptrdiff_t GetDeltaElems(T* wrapped_ptr1, 109 T* wrapped_ptr2) { 110 return wrapped_ptr1 - wrapped_ptr2; 111 } 112 113 // Returns a copy of a wrapped pointer, without making an assertion on whether 114 // memory was freed or not. 115 template <typename T> DuplicateRawPtrAsanUnownedImpl116 PA_ALWAYS_INLINE static constexpr T* Duplicate(T* wrapped_ptr) { 117 return wrapped_ptr; 118 } 119 120 template <typename T> ProbeForLowSeverityLifetimeIssueRawPtrAsanUnownedImpl121 static void ProbeForLowSeverityLifetimeIssue(T* wrapped_ptr) { 122 if (!MayDangle && wrapped_ptr) { 123 const volatile void* probe_ptr = 124 reinterpret_cast<const volatile void*>(wrapped_ptr); 125 if (!LikelySmuggledScalar(probe_ptr) && 126 !EndOfAliveAllocation(probe_ptr, IsAdjustablePtr)) { 127 reinterpret_cast<const volatile uint8_t*>(probe_ptr)[0]; 128 } 129 } 130 } 131 132 // `WrapRawPtrForDuplication` and `UnsafelyUnwrapPtrForDuplication` are used 133 // to create a new raw_ptr<T> from another raw_ptr<T> of a different flavor. 134 template <typename T> WrapRawPtrForDuplicationRawPtrAsanUnownedImpl135 PA_ALWAYS_INLINE static constexpr T* WrapRawPtrForDuplication(T* ptr) { 136 return ptr; 137 } 138 139 template <typename T> UnsafelyUnwrapPtrForDuplicationRawPtrAsanUnownedImpl140 PA_ALWAYS_INLINE static constexpr T* UnsafelyUnwrapPtrForDuplication( 141 T* wrapped_ptr) { 142 return wrapped_ptr; 143 } 144 145 template <typename T> TraceRawPtrAsanUnownedImpl146 static constexpr void Trace(uint64_t owner_id, T* wrapped_ptr) {} UntraceRawPtrAsanUnownedImpl147 static constexpr void Untrace(uint64_t owner_id) {} 148 149 // This is for accounting only, used by unit tests. IncrementSwapCountForTestRawPtrAsanUnownedImpl150 PA_ALWAYS_INLINE static constexpr void IncrementSwapCountForTest() {} IncrementLessCountForTestRawPtrAsanUnownedImpl151 PA_ALWAYS_INLINE static constexpr void IncrementLessCountForTest() {} 152 }; 153 154 } // namespace base::internal 155 156 #endif // PARTITION_ALLOC_POINTERS_RAW_PTR_ASAN_UNOWNED_IMPL_H_ 157