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