1 //===-- asan_allocator.h ----------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is a part of AddressSanitizer, an address sanity checker. 11 // 12 // ASan-private header for asan_allocator.cc. 13 //===----------------------------------------------------------------------===// 14 15 #ifndef ASAN_ALLOCATOR_H 16 #define ASAN_ALLOCATOR_H 17 18 #include "asan_internal.h" 19 #include "asan_interceptors.h" 20 21 namespace __asan { 22 23 static const size_t kNumberOfSizeClasses = 255; 24 struct AsanChunk; 25 26 class AsanChunkFifoList { 27 public: AsanChunkFifoList(LinkerInitialized)28 explicit AsanChunkFifoList(LinkerInitialized) { } AsanChunkFifoList()29 AsanChunkFifoList() { clear(); } 30 void Push(AsanChunk *n); 31 void PushList(AsanChunkFifoList *q); 32 AsanChunk *Pop(); size()33 size_t size() { return size_; } clear()34 void clear() { 35 first_ = last_ = NULL; 36 size_ = 0; 37 } 38 private: 39 AsanChunk *first_; 40 AsanChunk *last_; 41 size_t size_; 42 }; 43 44 struct AsanThreadLocalMallocStorage { AsanThreadLocalMallocStorageAsanThreadLocalMallocStorage45 explicit AsanThreadLocalMallocStorage(LinkerInitialized x) 46 : quarantine_(x) { } AsanThreadLocalMallocStorageAsanThreadLocalMallocStorage47 AsanThreadLocalMallocStorage() { 48 CHECK(REAL(memset)); 49 REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage)); 50 } 51 52 AsanChunkFifoList quarantine_; 53 AsanChunk *free_lists_[kNumberOfSizeClasses]; 54 void CommitBack(); 55 }; 56 57 // Fake stack frame contains local variables of one function. 58 // This struct should fit into a stack redzone (32 bytes). 59 struct FakeFrame { 60 uintptr_t magic; // Modified by the instrumented code. 61 uintptr_t descr; // Modified by the instrumented code. 62 FakeFrame *next; 63 uint64_t real_stack : 48; 64 uint64_t size_minus_one : 16; 65 }; 66 67 struct FakeFrameFifo { 68 public: 69 void FifoPush(FakeFrame *node); 70 FakeFrame *FifoPop(); 71 private: 72 FakeFrame *first_, *last_; 73 }; 74 75 class FakeFrameLifo { 76 public: LifoPush(FakeFrame * node)77 void LifoPush(FakeFrame *node) { 78 node->next = top_; 79 top_ = node; 80 } LifoPop()81 void LifoPop() { 82 CHECK(top_); 83 top_ = top_->next; 84 } top()85 FakeFrame *top() { return top_; } 86 private: 87 FakeFrame *top_; 88 }; 89 90 // For each thread we create a fake stack and place stack objects on this fake 91 // stack instead of the real stack. The fake stack is not really a stack but 92 // a fast malloc-like allocator so that when a function exits the fake stack 93 // is not poped but remains there for quite some time until gets used again. 94 // So, we poison the objects on the fake stack when function returns. 95 // It helps us find use-after-return bugs. 96 // We can not rely on __asan_stack_free being called on every function exit, 97 // so we maintain a lifo list of all current fake frames and update it on every 98 // call to __asan_stack_malloc. 99 class FakeStack { 100 public: 101 FakeStack(); FakeStack(LinkerInitialized)102 explicit FakeStack(LinkerInitialized) {} 103 void Init(size_t stack_size); StopUsingFakeStack()104 void StopUsingFakeStack() { alive_ = false; } 105 void Cleanup(); 106 uintptr_t AllocateStack(size_t size, size_t real_stack); 107 static void OnFree(size_t ptr, size_t size, size_t real_stack); 108 // Return the bottom of the maped region. 109 uintptr_t AddrIsInFakeStack(uintptr_t addr); StackSize()110 bool StackSize() { return stack_size_; } 111 private: 112 static const size_t kMinStackFrameSizeLog = 9; // Min frame is 512B. 113 static const size_t kMaxStackFrameSizeLog = 16; // Max stack frame is 64K. 114 static const size_t kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog; 115 static const size_t kNumberOfSizeClasses = 116 kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1; 117 118 bool AddrIsInSizeClass(uintptr_t addr, size_t size_class); 119 120 // Each size class should be large enough to hold all frames. 121 size_t ClassMmapSize(size_t size_class); 122 ClassSize(size_t size_class)123 size_t ClassSize(size_t size_class) { 124 return 1UL << (size_class + kMinStackFrameSizeLog); 125 } 126 127 void DeallocateFrame(FakeFrame *fake_frame); 128 129 size_t ComputeSizeClass(size_t alloc_size); 130 void AllocateOneSizeClass(size_t size_class); 131 132 size_t stack_size_; 133 bool alive_; 134 135 uintptr_t allocated_size_classes_[kNumberOfSizeClasses]; 136 FakeFrameFifo size_classes_[kNumberOfSizeClasses]; 137 FakeFrameLifo call_stack_; 138 }; 139 140 void *asan_memalign(size_t alignment, size_t size, AsanStackTrace *stack); 141 void asan_free(void *ptr, AsanStackTrace *stack); 142 143 void *asan_malloc(size_t size, AsanStackTrace *stack); 144 void *asan_calloc(size_t nmemb, size_t size, AsanStackTrace *stack); 145 void *asan_realloc(void *p, size_t size, AsanStackTrace *stack); 146 void *asan_valloc(size_t size, AsanStackTrace *stack); 147 void *asan_pvalloc(size_t size, AsanStackTrace *stack); 148 149 int asan_posix_memalign(void **memptr, size_t alignment, size_t size, 150 AsanStackTrace *stack); 151 size_t asan_malloc_usable_size(void *ptr, AsanStackTrace *stack); 152 153 size_t asan_mz_size(const void *ptr); 154 void asan_mz_force_lock(); 155 void asan_mz_force_unlock(); 156 void DescribeHeapAddress(uintptr_t addr, size_t access_size); 157 158 } // namespace __asan 159 #endif // ASAN_ALLOCATOR_H 160