asan_fake_stack.h revision 7a0bba457ee05ced3adf37a0c0790d0ed23a5446
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 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 113COMPILER_CHECK(sizeof(FakeStack) <= (1 << 17)); 114 115} // namespace __asan 116 117#endif // ASAN_FAKE_STACK_H 118