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, tag: 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 | |