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