1244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany//===-- asan_fake_stack.h ---------------------------------------*- C++ -*-===//
2244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany//
3244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany//                     The LLVM Compiler Infrastructure
4244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany//
5244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany// This file is distributed under the University of Illinois Open Source
6244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany// License. See LICENSE.TXT for details.
7244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany//
8244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany//===----------------------------------------------------------------------===//
9244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany//
10244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany// This file is a part of AddressSanitizer, an address sanity checker.
11244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany//
12244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany// ASan-private header for asan_fake_stack.cc
13244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany//===----------------------------------------------------------------------===//
14244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
15244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany#ifndef ASAN_FAKE_STACK_H
16244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany#define ASAN_FAKE_STACK_H
17244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
18244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryanynamespace __asan {
19244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
20244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany// Fake stack frame contains local variables of one function.
21244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryanystruct FakeFrame {
22244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  uptr magic;  // Modified by the instrumented code.
23244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  uptr descr;  // Modified by the instrumented code.
24ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany  uptr pc;     // Modified by the instrumented code.
25244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  u64 real_stack     : 48;
26244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  u64 size_minus_one : 16;
27ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany  // End of the first 32 bytes.
28ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany  // The rest should not be used when the frame is active.
29ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany  FakeFrame *next;
30244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany};
31244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
32244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryanystruct FakeFrameFifo {
33244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany public:
34244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  void FifoPush(FakeFrame *node);
35244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  FakeFrame *FifoPop();
36244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany private:
37244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  FakeFrame *first_, *last_;
38244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany};
39244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
40ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryanytemplate<uptr kMaxNumberOfFrames>
41244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryanyclass FakeFrameLifo {
42244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany public:
43ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany  explicit FakeFrameLifo(LinkerInitialized) {}
44ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany  FakeFrameLifo() : n_frames_(0) {}
45244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  void LifoPush(FakeFrame *node) {
46ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany    CHECK_LT(n_frames_, kMaxNumberOfFrames);
47ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany    frames_[n_frames_++] = node;
48244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  }
49244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  void LifoPop() {
50ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany    CHECK(n_frames_);
51ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany    n_frames_--;
52ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany  }
53ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany  FakeFrame *top() {
54ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany    if (n_frames_ == 0)
55ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany      return 0;
5637f9464fc0fa4df2acf04264c52ba542d0e3d3fbKostya Serebryany    return frames_[n_frames_ - 1];
57244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  }
58244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany private:
59ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany  uptr n_frames_;
60ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany  FakeFrame *frames_[kMaxNumberOfFrames];
61244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany};
62244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
63244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany// For each thread we create a fake stack and place stack objects on this fake
64244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany// stack instead of the real stack. The fake stack is not really a stack but
65244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany// a fast malloc-like allocator so that when a function exits the fake stack
66244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany// is not poped but remains there for quite some time until gets used again.
67244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany// So, we poison the objects on the fake stack when function returns.
68244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany// It helps us find use-after-return bugs.
69244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany// We can not rely on __asan_stack_free being called on every function exit,
70244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany// so we maintain a lifo list of all current fake frames and update it on every
71244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany// call to __asan_stack_malloc.
72244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryanyclass FakeStack {
73244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany public:
74244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  void Init(uptr stack_size);
75244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  void StopUsingFakeStack() { alive_ = false; }
76244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  void Cleanup();
77244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  uptr AllocateStack(uptr size, uptr real_stack);
78244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  static void OnFree(uptr ptr, uptr size, uptr real_stack);
79244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  // Return the bottom of the maped region.
80244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  uptr AddrIsInFakeStack(uptr addr);
815e97ba38b00eb843a55189bb913b445cbe620894Timur Iskhodzhanov  uptr StackSize() const { return stack_size_; }
82244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
83244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany private:
84244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  static const uptr kMinStackFrameSizeLog = 9;  // Min frame is 512B.
85244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  static const uptr kMaxStackFrameSizeLog = 16;  // Max stack frame is 64K.
86244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
87244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  static const uptr kNumberOfSizeClasses =
88244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany      kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
897a0bba457ee05ced3adf37a0c0790d0ed23a5446Kostya Serebryany  static const uptr kMaxRecursionDepth = 15000;
90244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
91244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  bool AddrIsInSizeClass(uptr addr, uptr size_class);
92244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
93244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  // Each size class should be large enough to hold all frames.
94244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  uptr ClassMmapSize(uptr size_class);
95244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
96244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  uptr ClassSize(uptr size_class) {
97244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany    return 1UL << (size_class + kMinStackFrameSizeLog);
98244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  }
99244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
100244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  void DeallocateFrame(FakeFrame *fake_frame);
101244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
102244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  uptr ComputeSizeClass(uptr alloc_size);
103244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  void AllocateOneSizeClass(uptr size_class);
104244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
105244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  uptr stack_size_;
106244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  bool   alive_;
107244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
108244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  uptr allocated_size_classes_[kNumberOfSizeClasses];
109244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany  FakeFrameFifo size_classes_[kNumberOfSizeClasses];
110ce0f7d13a6d2f1c141bc247aa75770cb88b38cb6Kostya Serebryany  FakeFrameLifo<kMaxRecursionDepth> call_stack_;
111244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany};
112244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
1137a0bba457ee05ced3adf37a0c0790d0ed23a5446Kostya SerebryanyCOMPILER_CHECK(sizeof(FakeStack) <= (1 << 17));
1147a0bba457ee05ced3adf37a0c0790d0ed23a5446Kostya Serebryany
115244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany}  // namespace __asan
116244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany
117244384d1a8a518c0b1ceaa5809333a91db1104b6Kostya Serebryany#endif  // ASAN_FAKE_STACK_H
118