1 //===-- hwasan_allocator.h --------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of HWAddressSanitizer. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef HWASAN_ALLOCATOR_H 14 #define HWASAN_ALLOCATOR_H 15 16 #include "hwasan.h" 17 #include "hwasan_interface_internal.h" 18 #include "hwasan_mapping.h" 19 #include "hwasan_poisoning.h" 20 #include "lsan/lsan_common.h" 21 #include "sanitizer_common/sanitizer_allocator.h" 22 #include "sanitizer_common/sanitizer_allocator_checks.h" 23 #include "sanitizer_common/sanitizer_allocator_interface.h" 24 #include "sanitizer_common/sanitizer_allocator_report.h" 25 #include "sanitizer_common/sanitizer_common.h" 26 #include "sanitizer_common/sanitizer_ring_buffer.h" 27 28 #if !defined(__aarch64__) && !defined(__x86_64__) && !(SANITIZER_RISCV64) 29 # error Unsupported platform 30 #endif 31 32 namespace __hwasan { 33 34 struct Metadata { 35 private: 36 atomic_uint64_t alloc_context_id; 37 u32 requested_size_low; 38 u16 requested_size_high; 39 atomic_uint8_t chunk_state; 40 u8 lsan_tag; 41 42 public: 43 inline void SetAllocated(u32 stack, u64 size); 44 inline void SetUnallocated(); 45 46 inline bool IsAllocated() const; 47 inline u64 GetRequestedSize() const; 48 inline u32 GetAllocStackId() const; 49 inline u32 GetAllocThreadId() const; 50 inline void SetLsanTag(__lsan::ChunkTag tag); 51 inline __lsan::ChunkTag GetLsanTag() const; 52 }; 53 static_assert(sizeof(Metadata) == 16); 54 55 struct HwasanMapUnmapCallback { 56 void OnMap(uptr p, uptr size) const { UpdateMemoryUsage(); } 57 void OnMapSecondary(uptr p, uptr size, uptr user_begin, 58 uptr user_size) const { 59 UpdateMemoryUsage(); 60 } 61 void OnUnmap(uptr p, uptr size) const { 62 // We are about to unmap a chunk of user memory. 63 // It can return as user-requested mmap() or another thread stack. 64 // Make it accessible with zero-tagged pointer. 65 TagMemory(p, size, 0); 66 } 67 }; 68 69 static const uptr kMaxAllowedMallocSize = 1UL << 40; // 1T 70 71 struct AP64 { 72 static const uptr kSpaceBeg = ~0ULL; 73 74 #if defined(HWASAN_ALIASING_MODE) 75 static const uptr kSpaceSize = 1ULL << kAddressTagShift; 76 typedef __sanitizer::DefaultSizeClassMap SizeClassMap; 77 #elif SANITIZER_LINUX && !SANITIZER_ANDROID 78 static const uptr kSpaceSize = 0x40000000000ULL; // 4T. 79 typedef __sanitizer::DefaultSizeClassMap SizeClassMap; 80 #else 81 static const uptr kSpaceSize = 0x2000000000ULL; // 128G. 82 typedef __sanitizer::VeryDenseSizeClassMap SizeClassMap; 83 #endif 84 85 static const uptr kMetadataSize = sizeof(Metadata); 86 using AddressSpaceView = LocalAddressSpaceView; 87 typedef HwasanMapUnmapCallback MapUnmapCallback; 88 static const uptr kFlags = 0; 89 }; 90 91 typedef SizeClassAllocator64<AP64> PrimaryAllocator; 92 typedef CombinedAllocator<PrimaryAllocator> Allocator; 93 typedef Allocator::AllocatorCache AllocatorCache; 94 95 void AllocatorThreadStart(AllocatorCache *cache); 96 void AllocatorThreadFinish(AllocatorCache *cache); 97 98 class HwasanChunkView { 99 public: 100 HwasanChunkView() : block_(0), metadata_(nullptr) {} 101 HwasanChunkView(uptr block, Metadata *metadata) 102 : block_(block), metadata_(metadata) {} 103 bool IsAllocated() const; // Checks if the memory is currently allocated 104 uptr Beg() const; // First byte of user memory 105 uptr End() const; // Last byte of user memory 106 uptr UsedSize() const; // Size requested by the user 107 uptr ActualSize() const; // Size allocated by the allocator. 108 u32 GetAllocStackId() const; 109 u32 GetAllocThreadId() const; 110 bool FromSmallHeap() const; 111 bool AddrIsInside(uptr addr) const; 112 113 private: 114 friend class __lsan::LsanMetadata; 115 uptr block_; 116 Metadata *const metadata_; 117 }; 118 119 HwasanChunkView FindHeapChunkByAddress(uptr address); 120 121 // Information about one (de)allocation that happened in the past. 122 // These are recorded in a thread-local ring buffer. 123 struct HeapAllocationRecord { 124 uptr tagged_addr; 125 u32 alloc_thread_id; 126 u32 alloc_context_id; 127 u32 free_context_id; 128 u32 requested_size; 129 }; 130 131 typedef RingBuffer<HeapAllocationRecord> HeapAllocationsRingBuffer; 132 133 void GetAllocatorStats(AllocatorStatCounters s); 134 135 } // namespace __hwasan 136 137 #endif // HWASAN_ALLOCATOR_H 138