asan_fake_stack.h revision 251034
1//===-- asan_fake_stack.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_fake_stack.cc 13//===----------------------------------------------------------------------===// 14 15#ifndef ASAN_FAKE_STACK_H 16#define ASAN_FAKE_STACK_H 17 18namespace __asan { 19 20// Fake stack frame contains local variables of one function. 21struct FakeFrame { 22 uptr magic; // Modified by the instrumented code. 23 uptr descr; // Modified by the instrumented code. 24 uptr pc; // Modified by the instrumented code. 25 u64 real_stack : 48; 26 u64 size_minus_one : 16; 27 // End of the first 32 bytes. 28 // The rest should not be used when the frame is active. 29 FakeFrame *next; 30}; 31 32struct FakeFrameFifo { 33 public: 34 void FifoPush(FakeFrame *node); 35 FakeFrame *FifoPop(); 36 private: 37 FakeFrame *first_, *last_; 38}; 39 40template<uptr kMaxNumberOfFrames> 41class FakeFrameLifo { 42 public: 43 explicit FakeFrameLifo(LinkerInitialized) {} 44 FakeFrameLifo() : n_frames_(0) {} 45 void LifoPush(FakeFrame *node) { 46 CHECK_LT(n_frames_, kMaxNumberOfFrames); 47 frames_[n_frames_++] = node; 48 } 49 void LifoPop() { 50 CHECK(n_frames_); 51 n_frames_--; 52 } 53 FakeFrame *top() { 54 if (n_frames_ == 0) 55 return 0; 56 return frames_[n_frames_ - 1]; 57 } 58 private: 59 uptr n_frames_; 60 FakeFrame *frames_[kMaxNumberOfFrames]; 61}; 62 63// For each thread we create a fake stack and place stack objects on this fake 64// stack instead of the real stack. The fake stack is not really a stack but 65// a fast malloc-like allocator so that when a function exits the fake stack 66// is not poped but remains there for quite some time until gets used again. 67// So, we poison the objects on the fake stack when function returns. 68// It helps us find use-after-return bugs. 69// We can not rely on __asan_stack_free being called on every function exit, 70// so we maintain a lifo list of all current fake frames and update it on every 71// call to __asan_stack_malloc. 72class FakeStack { 73 public: 74 FakeStack(); 75 explicit FakeStack(LinkerInitialized x) : call_stack_(x) {} 76 void Init(uptr stack_size); 77 void StopUsingFakeStack() { alive_ = false; } 78 void Cleanup(); 79 uptr AllocateStack(uptr size, uptr real_stack); 80 static void OnFree(uptr ptr, uptr size, uptr real_stack); 81 // Return the bottom of the maped region. 82 uptr AddrIsInFakeStack(uptr addr); 83 bool StackSize() { return stack_size_; } 84 85 private: 86 static const uptr kMinStackFrameSizeLog = 9; // Min frame is 512B. 87 static const uptr kMaxStackFrameSizeLog = 16; // Max stack frame is 64K. 88 static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog; 89 static const uptr kNumberOfSizeClasses = 90 kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1; 91 static const uptr kMaxRecursionDepth = 1023; 92 93 bool AddrIsInSizeClass(uptr addr, uptr size_class); 94 95 // Each size class should be large enough to hold all frames. 96 uptr ClassMmapSize(uptr size_class); 97 98 uptr ClassSize(uptr size_class) { 99 return 1UL << (size_class + kMinStackFrameSizeLog); 100 } 101 102 void DeallocateFrame(FakeFrame *fake_frame); 103 104 uptr ComputeSizeClass(uptr alloc_size); 105 void AllocateOneSizeClass(uptr size_class); 106 107 uptr stack_size_; 108 bool alive_; 109 110 uptr allocated_size_classes_[kNumberOfSizeClasses]; 111 FakeFrameFifo size_classes_[kNumberOfSizeClasses]; 112 FakeFrameLifo<kMaxRecursionDepth> call_stack_; 113}; 114 115} // namespace __asan 116 117#endif // ASAN_FAKE_STACK_H 118