Home | History | Annotate | Download | only in asan
      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