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 18 namespace __asan { 19 20 // Fake stack frame contains local variables of one function. 21 struct 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 32 struct FakeFrameFifo { 33 public: 34 void FifoPush(FakeFrame *node); 35 FakeFrame *FifoPop(); 36 private: 37 FakeFrame *first_, *last_; 38 }; 39 40 template<uptr kMaxNumberOfFrames> 41 class 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. 72 class FakeStack { 73 public: 74 void Init(uptr stack_size); 75 void StopUsingFakeStack() { alive_ = false; } 76 void Cleanup(); 77 uptr AllocateStack(uptr size, uptr real_stack); 78 static void OnFree(uptr ptr, uptr size, uptr real_stack); 79 // Return the bottom of the maped region. 80 uptr AddrIsInFakeStack(uptr addr); 81 uptr StackSize() const { return stack_size_; } 82 83 private: 84 static const uptr kMinStackFrameSizeLog = 9; // Min frame is 512B. 85 static const uptr kMaxStackFrameSizeLog = 16; // Max stack frame is 64K. 86 static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog; 87 static const uptr kNumberOfSizeClasses = 88 kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1; 89 static const uptr kMaxRecursionDepth = 15000; 90 91 bool AddrIsInSizeClass(uptr addr, uptr size_class); 92 93 // Each size class should be large enough to hold all frames. 94 uptr ClassMmapSize(uptr size_class); 95 96 uptr ClassSize(uptr size_class) { 97 return 1UL << (size_class + kMinStackFrameSizeLog); 98 } 99 100 void DeallocateFrame(FakeFrame *fake_frame); 101 102 uptr ComputeSizeClass(uptr alloc_size); 103 void AllocateOneSizeClass(uptr size_class); 104 105 uptr stack_size_; 106 bool alive_; 107 108 uptr allocated_size_classes_[kNumberOfSizeClasses]; 109 FakeFrameFifo size_classes_[kNumberOfSizeClasses]; 110 FakeFrameLifo<kMaxRecursionDepth> call_stack_; 111 }; 112 113 COMPILER_CHECK(sizeof(FakeStack) <= (1 << 17)); 114 115 } // namespace __asan 116 117 #endif // ASAN_FAKE_STACK_H 118