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_ALLOCATOR_PARTITION_ALLOCATOR_POINTERS_RAW_PTR_ASAN_UNOWNED_IMPL_H_ 6 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_POINTERS_RAW_PTR_ASAN_UNOWNED_IMPL_H_ 7 8 #include <stddef.h> 9 10 #include <type_traits> 11 12 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h" 13 #include "base/allocator/partition_allocator/partition_alloc_base/cxx20_is_constant_evaluated.h" 14 #include "base/allocator/partition_allocator/partition_alloc_buildflags.h" 15 #include "base/allocator/partition_allocator/partition_alloc_forward.h" 16 17 #if !BUILDFLAG(USE_ASAN_UNOWNED_PTR) 18 #error "Included under wrong build option" 19 #endif 20 21 namespace base::internal { 22 23 bool EndOfAliveAllocation(const volatile void* ptr, bool is_adjustable_ptr); 24 bool LikelySmuggledScalar(const volatile void* ptr); 25 26 template <bool IsAdjustablePtr> 27 struct RawPtrAsanUnownedImpl { 28 // The first two are needed for correctness. The last one isn't technically a 29 // must, but better to set it. 30 static constexpr bool kMustZeroOnInit = true; 31 static constexpr bool kMustZeroOnMove = true; 32 static constexpr bool kMustZeroOnDestruct = true; 33 34 // Wraps a pointer. 35 template <typename T> WrapRawPtrRawPtrAsanUnownedImpl36 PA_ALWAYS_INLINE static constexpr T* WrapRawPtr(T* ptr) { 37 return ptr; 38 } 39 40 // Notifies the allocator when a wrapped pointer is being removed or replaced. 41 template <typename T> ReleaseWrappedPtrRawPtrAsanUnownedImpl42 PA_ALWAYS_INLINE static constexpr void ReleaseWrappedPtr(T* wrapped_ptr) { 43 if (!partition_alloc::internal::base::is_constant_evaluated()) { 44 ProbeForLowSeverityLifetimeIssue(wrapped_ptr); 45 } 46 } 47 48 // Unwraps the pointer, while asserting that memory hasn't been freed. The 49 // function is allowed to crash on nullptr. 50 template <typename T> SafelyUnwrapPtrForDereferenceRawPtrAsanUnownedImpl51 PA_ALWAYS_INLINE static constexpr T* SafelyUnwrapPtrForDereference( 52 T* wrapped_ptr) { 53 // ASAN will catch use of dereferenced ptr without additional probing. 54 return wrapped_ptr; 55 } 56 57 // Unwraps the pointer, while asserting that memory hasn't been freed. The 58 // function must handle nullptr gracefully. 59 template <typename T> SafelyUnwrapPtrForExtractionRawPtrAsanUnownedImpl60 PA_ALWAYS_INLINE static constexpr T* SafelyUnwrapPtrForExtraction( 61 T* wrapped_ptr) { 62 if (!partition_alloc::internal::base::is_constant_evaluated()) { 63 ProbeForLowSeverityLifetimeIssue(wrapped_ptr); 64 } 65 return wrapped_ptr; 66 } 67 68 // Unwraps the pointer, without making an assertion on whether memory was 69 // freed or not. 70 template <typename T> UnsafelyUnwrapPtrForComparisonRawPtrAsanUnownedImpl71 PA_ALWAYS_INLINE static constexpr T* UnsafelyUnwrapPtrForComparison( 72 T* wrapped_ptr) { 73 return wrapped_ptr; 74 } 75 76 // Upcasts the wrapped pointer. 77 template <typename To, typename From> UpcastRawPtrAsanUnownedImpl78 PA_ALWAYS_INLINE static constexpr To* Upcast(From* wrapped_ptr) { 79 static_assert(std::is_convertible<From*, To*>::value, 80 "From must be convertible to To."); 81 // Note, this cast may change the address if upcasting to base that lies in 82 // the middle of the derived object. 83 return wrapped_ptr; 84 } 85 86 // Advance the wrapped pointer by `delta_elems`. 87 template < 88 typename T, 89 typename Z, 90 typename = 91 std::enable_if_t<partition_alloc::internal::is_offset_type<Z>, void>> AdvanceRawPtrAsanUnownedImpl92 PA_ALWAYS_INLINE static constexpr T* Advance(T* wrapped_ptr, Z delta_elems) { 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>> RetreatRawPtrAsanUnownedImpl102 PA_ALWAYS_INLINE static constexpr T* Retreat(T* wrapped_ptr, Z delta_elems) { 103 return wrapped_ptr - delta_elems; 104 } 105 106 template <typename T> GetDeltaElemsRawPtrAsanUnownedImpl107 PA_ALWAYS_INLINE static constexpr ptrdiff_t GetDeltaElems(T* wrapped_ptr1, 108 T* wrapped_ptr2) { 109 return wrapped_ptr1 - wrapped_ptr2; 110 } 111 112 // Returns a copy of a wrapped pointer, without making an assertion on whether 113 // memory was freed or not. 114 template <typename T> DuplicateRawPtrAsanUnownedImpl115 PA_ALWAYS_INLINE static constexpr T* Duplicate(T* wrapped_ptr) { 116 return wrapped_ptr; 117 } 118 119 template <typename T> ProbeForLowSeverityLifetimeIssueRawPtrAsanUnownedImpl120 static void ProbeForLowSeverityLifetimeIssue(T* wrapped_ptr) { 121 if (wrapped_ptr) { 122 const volatile void* probe_ptr = 123 reinterpret_cast<const volatile void*>(wrapped_ptr); 124 if (!LikelySmuggledScalar(probe_ptr) && 125 !EndOfAliveAllocation(probe_ptr, IsAdjustablePtr)) { 126 reinterpret_cast<const volatile uint8_t*>(probe_ptr)[0]; 127 } 128 } 129 } 130 131 // `WrapRawPtrForDuplication` and `UnsafelyUnwrapPtrForDuplication` are used 132 // to create a new raw_ptr<T> from another raw_ptr<T> of a different flavor. 133 template <typename T> WrapRawPtrForDuplicationRawPtrAsanUnownedImpl134 PA_ALWAYS_INLINE static constexpr T* WrapRawPtrForDuplication(T* ptr) { 135 return ptr; 136 } 137 138 template <typename T> UnsafelyUnwrapPtrForDuplicationRawPtrAsanUnownedImpl139 PA_ALWAYS_INLINE static constexpr T* UnsafelyUnwrapPtrForDuplication( 140 T* wrapped_ptr) { 141 return wrapped_ptr; 142 } 143 144 // This is for accounting only, used by unit tests. IncrementSwapCountForTestRawPtrAsanUnownedImpl145 PA_ALWAYS_INLINE static constexpr void IncrementSwapCountForTest() {} IncrementLessCountForTestRawPtrAsanUnownedImpl146 PA_ALWAYS_INLINE static constexpr void IncrementLessCountForTest() {} 147 PA_ALWAYS_INLINE static constexpr void IncrementPointerToMemberOperatorCountForTestRawPtrAsanUnownedImpl148 IncrementPointerToMemberOperatorCountForTest() {} 149 }; 150 151 } // namespace base::internal 152 153 #endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_POINTERS_RAW_PTR_ASAN_UNOWNED_IMPL_H_ 154