10b57cec5SDimitry Andric //===-- hwasan_allocator.h --------------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file is a part of HWAddressSanitizer. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #ifndef HWASAN_ALLOCATOR_H 140b57cec5SDimitry Andric #define HWASAN_ALLOCATOR_H 150b57cec5SDimitry Andric 16fe6060f1SDimitry Andric #include "hwasan.h" 17fe6060f1SDimitry Andric #include "hwasan_interface_internal.h" 18fe6060f1SDimitry Andric #include "hwasan_mapping.h" 19fe6060f1SDimitry Andric #include "hwasan_poisoning.h" 20bdd1243dSDimitry Andric #include "lsan/lsan_common.h" 210b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_allocator.h" 220b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_allocator_checks.h" 230b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_allocator_interface.h" 240b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_allocator_report.h" 250b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_common.h" 260b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_ring_buffer.h" 270b57cec5SDimitry Andric 28bdd1243dSDimitry Andric #if !defined(__aarch64__) && !defined(__x86_64__) && !(SANITIZER_RISCV64) 290b57cec5SDimitry Andric # error Unsupported platform 300b57cec5SDimitry Andric #endif 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric namespace __hwasan { 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric struct Metadata { 35bdd1243dSDimitry Andric private: 36bdd1243dSDimitry Andric atomic_uint64_t alloc_context_id; 37e8d8bef9SDimitry Andric u32 requested_size_low; 38bdd1243dSDimitry Andric u16 requested_size_high; 39bdd1243dSDimitry Andric atomic_uint8_t chunk_state; 40bdd1243dSDimitry Andric u8 lsan_tag; 41bdd1243dSDimitry Andric 42bdd1243dSDimitry Andric public: 43bdd1243dSDimitry Andric inline void SetAllocated(u32 stack, u64 size); 44bdd1243dSDimitry Andric inline void SetUnallocated(); 45bdd1243dSDimitry Andric 46bdd1243dSDimitry Andric inline bool IsAllocated() const; 47bdd1243dSDimitry Andric inline u64 GetRequestedSize() const; 48bdd1243dSDimitry Andric inline u32 GetAllocStackId() const; 49*06c3fb27SDimitry Andric inline u32 GetAllocThreadId() const; 50bdd1243dSDimitry Andric inline void SetLsanTag(__lsan::ChunkTag tag); 51bdd1243dSDimitry Andric inline __lsan::ChunkTag GetLsanTag() const; 520b57cec5SDimitry Andric }; 53bdd1243dSDimitry Andric static_assert(sizeof(Metadata) == 16); 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric struct HwasanMapUnmapCallback { OnMapHwasanMapUnmapCallback560b57cec5SDimitry Andric void OnMap(uptr p, uptr size) const { UpdateMemoryUsage(); } OnMapSecondaryHwasanMapUnmapCallback57*06c3fb27SDimitry Andric void OnMapSecondary(uptr p, uptr size, uptr user_begin, 58*06c3fb27SDimitry Andric uptr user_size) const { 59*06c3fb27SDimitry Andric UpdateMemoryUsage(); 60*06c3fb27SDimitry Andric } OnUnmapHwasanMapUnmapCallback610b57cec5SDimitry Andric void OnUnmap(uptr p, uptr size) const { 620b57cec5SDimitry Andric // We are about to unmap a chunk of user memory. 630b57cec5SDimitry Andric // It can return as user-requested mmap() or another thread stack. 640b57cec5SDimitry Andric // Make it accessible with zero-tagged pointer. 650b57cec5SDimitry Andric TagMemory(p, size, 0); 660b57cec5SDimitry Andric } 670b57cec5SDimitry Andric }; 680b57cec5SDimitry Andric 69e8d8bef9SDimitry Andric static const uptr kMaxAllowedMallocSize = 1UL << 40; // 1T 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric struct AP64 { 720b57cec5SDimitry Andric static const uptr kSpaceBeg = ~0ULL; 73fe6060f1SDimitry Andric 74fe6060f1SDimitry Andric #if defined(HWASAN_ALIASING_MODE) 75fe6060f1SDimitry Andric static const uptr kSpaceSize = 1ULL << kAddressTagShift; 76*06c3fb27SDimitry Andric typedef __sanitizer::DefaultSizeClassMap SizeClassMap; 77*06c3fb27SDimitry Andric #elif SANITIZER_LINUX && !SANITIZER_ANDROID 78*06c3fb27SDimitry Andric static const uptr kSpaceSize = 0x40000000000ULL; // 4T. 79*06c3fb27SDimitry Andric typedef __sanitizer::DefaultSizeClassMap SizeClassMap; 80fe6060f1SDimitry Andric #else 81*06c3fb27SDimitry Andric static const uptr kSpaceSize = 0x2000000000ULL; // 128G. 820b57cec5SDimitry Andric typedef __sanitizer::VeryDenseSizeClassMap SizeClassMap; 83*06c3fb27SDimitry Andric #endif 84*06c3fb27SDimitry Andric 85*06c3fb27SDimitry Andric static const uptr kMetadataSize = sizeof(Metadata); 860b57cec5SDimitry Andric using AddressSpaceView = LocalAddressSpaceView; 870b57cec5SDimitry Andric typedef HwasanMapUnmapCallback MapUnmapCallback; 880b57cec5SDimitry Andric static const uptr kFlags = 0; 890b57cec5SDimitry Andric }; 90*06c3fb27SDimitry Andric 910b57cec5SDimitry Andric typedef SizeClassAllocator64<AP64> PrimaryAllocator; 920b57cec5SDimitry Andric typedef CombinedAllocator<PrimaryAllocator> Allocator; 930b57cec5SDimitry Andric typedef Allocator::AllocatorCache AllocatorCache; 940b57cec5SDimitry Andric 95*06c3fb27SDimitry Andric void AllocatorThreadStart(AllocatorCache *cache); 96*06c3fb27SDimitry Andric void AllocatorThreadFinish(AllocatorCache *cache); 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric class HwasanChunkView { 990b57cec5SDimitry Andric public: HwasanChunkView()1000b57cec5SDimitry Andric HwasanChunkView() : block_(0), metadata_(nullptr) {} HwasanChunkView(uptr block,Metadata * metadata)1010b57cec5SDimitry Andric HwasanChunkView(uptr block, Metadata *metadata) 1020b57cec5SDimitry Andric : block_(block), metadata_(metadata) {} 1030b57cec5SDimitry Andric bool IsAllocated() const; // Checks if the memory is currently allocated 1040b57cec5SDimitry Andric uptr Beg() const; // First byte of user memory 1050b57cec5SDimitry Andric uptr End() const; // Last byte of user memory 1060b57cec5SDimitry Andric uptr UsedSize() const; // Size requested by the user 1070b57cec5SDimitry Andric uptr ActualSize() const; // Size allocated by the allocator. 1080b57cec5SDimitry Andric u32 GetAllocStackId() const; 109*06c3fb27SDimitry Andric u32 GetAllocThreadId() const; 1100b57cec5SDimitry Andric bool FromSmallHeap() const; 111bdd1243dSDimitry Andric bool AddrIsInside(uptr addr) const; 112bdd1243dSDimitry Andric 1130b57cec5SDimitry Andric private: 114bdd1243dSDimitry Andric friend class __lsan::LsanMetadata; 1150b57cec5SDimitry Andric uptr block_; 1160b57cec5SDimitry Andric Metadata *const metadata_; 1170b57cec5SDimitry Andric }; 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric HwasanChunkView FindHeapChunkByAddress(uptr address); 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric // Information about one (de)allocation that happened in the past. 1220b57cec5SDimitry Andric // These are recorded in a thread-local ring buffer. 1230b57cec5SDimitry Andric struct HeapAllocationRecord { 1240b57cec5SDimitry Andric uptr tagged_addr; 125*06c3fb27SDimitry Andric u32 alloc_thread_id; 1260b57cec5SDimitry Andric u32 alloc_context_id; 1270b57cec5SDimitry Andric u32 free_context_id; 1280b57cec5SDimitry Andric u32 requested_size; 1290b57cec5SDimitry Andric }; 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric typedef RingBuffer<HeapAllocationRecord> HeapAllocationsRingBuffer; 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric void GetAllocatorStats(AllocatorStatCounters s); 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric } // namespace __hwasan 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric #endif // HWASAN_ALLOCATOR_H 138