xref: /freebsd/contrib/llvm-project/compiler-rt/lib/hwasan/hwasan_allocator.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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