1//===-- asan_allocator.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_allocator.cc.
13//===----------------------------------------------------------------------===//
14
15#ifndef ASAN_ALLOCATOR_H
16#define ASAN_ALLOCATOR_H
17
18#include "asan_internal.h"
19#include "asan_interceptors.h"
20
21namespace __asan {
22
23static const size_t kNumberOfSizeClasses = 255;
24struct AsanChunk;
25
26class AsanChunkFifoList {
27 public:
28  explicit AsanChunkFifoList(LinkerInitialized) { }
29  AsanChunkFifoList() { clear(); }
30  void Push(AsanChunk *n);
31  void PushList(AsanChunkFifoList *q);
32  AsanChunk *Pop();
33  size_t size() { return size_; }
34  void clear() {
35    first_ = last_ = NULL;
36    size_ = 0;
37  }
38 private:
39  AsanChunk *first_;
40  AsanChunk *last_;
41  size_t size_;
42};
43
44struct AsanThreadLocalMallocStorage {
45  explicit AsanThreadLocalMallocStorage(LinkerInitialized x)
46      : quarantine_(x) { }
47  AsanThreadLocalMallocStorage() {
48    CHECK(REAL(memset));
49    REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage));
50  }
51
52  AsanChunkFifoList quarantine_;
53  AsanChunk *free_lists_[kNumberOfSizeClasses];
54  void CommitBack();
55};
56
57// Fake stack frame contains local variables of one function.
58// This struct should fit into a stack redzone (32 bytes).
59struct FakeFrame {
60  uintptr_t magic;  // Modified by the instrumented code.
61  uintptr_t descr;  // Modified by the instrumented code.
62  FakeFrame *next;
63  uint64_t real_stack     : 48;
64  uint64_t size_minus_one : 16;
65};
66
67struct FakeFrameFifo {
68 public:
69  void FifoPush(FakeFrame *node);
70  FakeFrame *FifoPop();
71 private:
72  FakeFrame *first_, *last_;
73};
74
75class FakeFrameLifo {
76 public:
77  void LifoPush(FakeFrame *node) {
78    node->next = top_;
79    top_ = node;
80  }
81  void LifoPop() {
82    CHECK(top_);
83    top_ = top_->next;
84  }
85  FakeFrame *top() { return top_; }
86 private:
87  FakeFrame *top_;
88};
89
90// For each thread we create a fake stack and place stack objects on this fake
91// stack instead of the real stack. The fake stack is not really a stack but
92// a fast malloc-like allocator so that when a function exits the fake stack
93// is not poped but remains there for quite some time until gets used again.
94// So, we poison the objects on the fake stack when function returns.
95// It helps us find use-after-return bugs.
96// We can not rely on __asan_stack_free being called on every function exit,
97// so we maintain a lifo list of all current fake frames and update it on every
98// call to __asan_stack_malloc.
99class FakeStack {
100 public:
101  FakeStack();
102  explicit FakeStack(LinkerInitialized) {}
103  void Init(size_t stack_size);
104  void StopUsingFakeStack() { alive_ = false; }
105  void Cleanup();
106  uintptr_t AllocateStack(size_t size, size_t real_stack);
107  static void OnFree(size_t ptr, size_t size, size_t real_stack);
108  // Return the bottom of the maped region.
109  uintptr_t AddrIsInFakeStack(uintptr_t addr);
110  bool StackSize() { return stack_size_; }
111 private:
112  static const size_t kMinStackFrameSizeLog = 9;  // Min frame is 512B.
113  static const size_t kMaxStackFrameSizeLog = 16;  // Max stack frame is 64K.
114  static const size_t kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
115  static const size_t kNumberOfSizeClasses =
116      kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
117
118  bool AddrIsInSizeClass(uintptr_t addr, size_t size_class);
119
120  // Each size class should be large enough to hold all frames.
121  size_t ClassMmapSize(size_t size_class);
122
123  size_t ClassSize(size_t size_class) {
124    return 1UL << (size_class + kMinStackFrameSizeLog);
125  }
126
127  void DeallocateFrame(FakeFrame *fake_frame);
128
129  size_t ComputeSizeClass(size_t alloc_size);
130  void AllocateOneSizeClass(size_t size_class);
131
132  size_t stack_size_;
133  bool   alive_;
134
135  uintptr_t allocated_size_classes_[kNumberOfSizeClasses];
136  FakeFrameFifo size_classes_[kNumberOfSizeClasses];
137  FakeFrameLifo call_stack_;
138};
139
140void *asan_memalign(size_t alignment, size_t size, AsanStackTrace *stack);
141void asan_free(void *ptr, AsanStackTrace *stack);
142
143void *asan_malloc(size_t size, AsanStackTrace *stack);
144void *asan_calloc(size_t nmemb, size_t size, AsanStackTrace *stack);
145void *asan_realloc(void *p, size_t size, AsanStackTrace *stack);
146void *asan_valloc(size_t size, AsanStackTrace *stack);
147void *asan_pvalloc(size_t size, AsanStackTrace *stack);
148
149int asan_posix_memalign(void **memptr, size_t alignment, size_t size,
150                          AsanStackTrace *stack);
151size_t asan_malloc_usable_size(void *ptr, AsanStackTrace *stack);
152
153size_t asan_mz_size(const void *ptr);
154void asan_mz_force_lock();
155void asan_mz_force_unlock();
156void DescribeHeapAddress(uintptr_t addr, size_t access_size);
157
158}  // namespace __asan
159#endif  // ASAN_ALLOCATOR_H
160