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 "sanitizer_common/sanitizer_allocator.h"
21 #include "sanitizer_common/sanitizer_allocator_checks.h"
22 #include "sanitizer_common/sanitizer_allocator_interface.h"
23 #include "sanitizer_common/sanitizer_allocator_report.h"
24 #include "sanitizer_common/sanitizer_common.h"
25 #include "sanitizer_common/sanitizer_ring_buffer.h"
26 
27 #if !defined(__aarch64__) && !defined(__x86_64__)
28 #error Unsupported platform
29 #endif
30 
31 namespace __hwasan {
32 
33 struct Metadata {
34   u32 requested_size_low;
35   u32 requested_size_high : 31;
36   u32 right_aligned : 1;
37   u32 alloc_context_id;
38   u64 get_requested_size() {
39     return (static_cast<u64>(requested_size_high) << 32) + requested_size_low;
40   }
41   void set_requested_size(u64 size) {
42     requested_size_low = size & ((1ul << 32) - 1);
43     requested_size_high = size >> 32;
44   }
45 };
46 
47 struct HwasanMapUnmapCallback {
48   void OnMap(uptr p, uptr size) const { UpdateMemoryUsage(); }
49   void OnUnmap(uptr p, uptr size) const {
50     // We are about to unmap a chunk of user memory.
51     // It can return as user-requested mmap() or another thread stack.
52     // Make it accessible with zero-tagged pointer.
53     TagMemory(p, size, 0);
54   }
55 };
56 
57 static const uptr kMaxAllowedMallocSize = 1UL << 40;  // 1T
58 
59 struct AP64 {
60   static const uptr kSpaceBeg = ~0ULL;
61 
62 #if defined(HWASAN_ALIASING_MODE)
63   static const uptr kSpaceSize = 1ULL << kAddressTagShift;
64 #else
65   static const uptr kSpaceSize = 0x2000000000ULL;
66 #endif
67   static const uptr kMetadataSize = sizeof(Metadata);
68   typedef __sanitizer::VeryDenseSizeClassMap SizeClassMap;
69   using AddressSpaceView = LocalAddressSpaceView;
70   typedef HwasanMapUnmapCallback MapUnmapCallback;
71   static const uptr kFlags = 0;
72 };
73 typedef SizeClassAllocator64<AP64> PrimaryAllocator;
74 typedef CombinedAllocator<PrimaryAllocator> Allocator;
75 typedef Allocator::AllocatorCache AllocatorCache;
76 
77 void AllocatorSwallowThreadLocalCache(AllocatorCache *cache);
78 
79 class HwasanChunkView {
80  public:
81   HwasanChunkView() : block_(0), metadata_(nullptr) {}
82   HwasanChunkView(uptr block, Metadata *metadata)
83       : block_(block), metadata_(metadata) {}
84   bool IsAllocated() const;    // Checks if the memory is currently allocated
85   uptr Beg() const;            // First byte of user memory
86   uptr End() const;            // Last byte of user memory
87   uptr UsedSize() const;       // Size requested by the user
88   uptr ActualSize() const;     // Size allocated by the allocator.
89   u32 GetAllocStackId() const;
90   bool FromSmallHeap() const;
91  private:
92   uptr block_;
93   Metadata *const metadata_;
94 };
95 
96 HwasanChunkView FindHeapChunkByAddress(uptr address);
97 
98 // Information about one (de)allocation that happened in the past.
99 // These are recorded in a thread-local ring buffer.
100 // TODO: this is currently 24 bytes (20 bytes + alignment).
101 // Compress it to 16 bytes or extend it to be more useful.
102 struct HeapAllocationRecord {
103   uptr tagged_addr;
104   u32  alloc_context_id;
105   u32  free_context_id;
106   u32  requested_size;
107 };
108 
109 typedef RingBuffer<HeapAllocationRecord> HeapAllocationsRingBuffer;
110 
111 void GetAllocatorStats(AllocatorStatCounters s);
112 
113 inline bool InTaggableRegion(uptr addr) {
114 #if defined(HWASAN_ALIASING_MODE)
115   // Aliases are mapped next to shadow so that the upper bits match the shadow
116   // base.
117   return (addr >> kTaggableRegionCheckShift) ==
118          (GetShadowOffset() >> kTaggableRegionCheckShift);
119 #endif
120   return true;
121 }
122 
123 } // namespace __hwasan
124 
125 #endif // HWASAN_ALLOCATOR_H
126