asan_allocator.h revision 2679f1904dc5d5eb2ce82014116764c5f5131a2b
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
21// We are in the process of transitioning from the old allocator (version 1)
22// to a new one (version 2). The change is quite intrusive so both allocators
23// will co-exist in the source base for a while. The actual allocator is chosen
24// at build time by redefining this macrozz.
25#define ASAN_ALLOCATOR_VERSION 1
26
27namespace __asan {
28
29static const uptr kNumberOfSizeClasses = 255;
30struct AsanChunk;
31
32class AsanChunkView {
33 public:
34  explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
35  bool IsValid() { return chunk_ != 0; }
36  uptr Beg();       // first byte of user memory.
37  uptr End();       // last byte of user memory.
38  uptr UsedSize();  // size requested by the user.
39  uptr AllocTid();
40  uptr FreeTid();
41  void GetAllocStack(StackTrace *stack);
42  void GetFreeStack(StackTrace *stack);
43  bool AddrIsInside(uptr addr, uptr access_size, uptr *offset);
44  bool AddrIsAtLeft(uptr addr, uptr access_size, uptr *offset);
45  bool AddrIsAtRight(uptr addr, uptr access_size, uptr *offset);
46 private:
47  AsanChunk *const chunk_;
48};
49
50AsanChunkView FindHeapChunkByAddress(uptr address);
51
52class AsanChunkFifoList {
53 public:
54  explicit AsanChunkFifoList(LinkerInitialized) { }
55  AsanChunkFifoList() { clear(); }
56  void Push(AsanChunk *n);
57  void PushList(AsanChunkFifoList *q);
58  AsanChunk *Pop();
59  uptr size() { return size_; }
60  void clear() {
61    first_ = last_ = 0;
62    size_ = 0;
63  }
64 private:
65  AsanChunk *first_;
66  AsanChunk *last_;
67  uptr size_;
68};
69
70struct AsanThreadLocalMallocStorage {
71  explicit AsanThreadLocalMallocStorage(LinkerInitialized x)
72      : quarantine_(x) { }
73  AsanThreadLocalMallocStorage() {
74    CHECK(REAL(memset));
75    REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage));
76  }
77
78  AsanChunkFifoList quarantine_;
79  AsanChunk *free_lists_[kNumberOfSizeClasses];
80  void CommitBack();
81};
82
83// Fake stack frame contains local variables of one function.
84// This struct should fit into a stack redzone (32 bytes).
85struct FakeFrame {
86  uptr magic;  // Modified by the instrumented code.
87  uptr descr;  // Modified by the instrumented code.
88  FakeFrame *next;
89  u64 real_stack     : 48;
90  u64 size_minus_one : 16;
91};
92
93struct FakeFrameFifo {
94 public:
95  void FifoPush(FakeFrame *node);
96  FakeFrame *FifoPop();
97 private:
98  FakeFrame *first_, *last_;
99};
100
101class FakeFrameLifo {
102 public:
103  void LifoPush(FakeFrame *node) {
104    node->next = top_;
105    top_ = node;
106  }
107  void LifoPop() {
108    CHECK(top_);
109    top_ = top_->next;
110  }
111  FakeFrame *top() { return top_; }
112 private:
113  FakeFrame *top_;
114};
115
116// For each thread we create a fake stack and place stack objects on this fake
117// stack instead of the real stack. The fake stack is not really a stack but
118// a fast malloc-like allocator so that when a function exits the fake stack
119// is not poped but remains there for quite some time until gets used again.
120// So, we poison the objects on the fake stack when function returns.
121// It helps us find use-after-return bugs.
122// We can not rely on __asan_stack_free being called on every function exit,
123// so we maintain a lifo list of all current fake frames and update it on every
124// call to __asan_stack_malloc.
125class FakeStack {
126 public:
127  FakeStack();
128  explicit FakeStack(LinkerInitialized) {}
129  void Init(uptr stack_size);
130  void StopUsingFakeStack() { alive_ = false; }
131  void Cleanup();
132  uptr AllocateStack(uptr size, uptr real_stack);
133  static void OnFree(uptr ptr, uptr size, uptr real_stack);
134  // Return the bottom of the maped region.
135  uptr AddrIsInFakeStack(uptr addr);
136  bool StackSize() { return stack_size_; }
137
138 private:
139  static const uptr kMinStackFrameSizeLog = 9;  // Min frame is 512B.
140  static const uptr kMaxStackFrameSizeLog = 16;  // Max stack frame is 64K.
141  static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
142  static const uptr kNumberOfSizeClasses =
143      kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
144
145  bool AddrIsInSizeClass(uptr addr, uptr size_class);
146
147  // Each size class should be large enough to hold all frames.
148  uptr ClassMmapSize(uptr size_class);
149
150  uptr ClassSize(uptr size_class) {
151    return 1UL << (size_class + kMinStackFrameSizeLog);
152  }
153
154  void DeallocateFrame(FakeFrame *fake_frame);
155
156  uptr ComputeSizeClass(uptr alloc_size);
157  void AllocateOneSizeClass(uptr size_class);
158
159  uptr stack_size_;
160  bool   alive_;
161
162  uptr allocated_size_classes_[kNumberOfSizeClasses];
163  FakeFrameFifo size_classes_[kNumberOfSizeClasses];
164  FakeFrameLifo call_stack_;
165};
166
167void *asan_memalign(uptr alignment, uptr size, StackTrace *stack);
168void asan_free(void *ptr, StackTrace *stack);
169
170void *asan_malloc(uptr size, StackTrace *stack);
171void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack);
172void *asan_realloc(void *p, uptr size, StackTrace *stack);
173void *asan_valloc(uptr size, StackTrace *stack);
174void *asan_pvalloc(uptr size, StackTrace *stack);
175
176int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
177                          StackTrace *stack);
178uptr asan_malloc_usable_size(void *ptr, StackTrace *stack);
179
180uptr asan_mz_size(const void *ptr);
181void asan_mz_force_lock();
182void asan_mz_force_unlock();
183
184// Log2 and RoundUpToPowerOfTwo should be inlined for performance.
185
186static inline uptr Log2(uptr x) {
187  CHECK(IsPowerOfTwo(x));
188#if !defined(_WIN32) || defined(__clang__)
189  return __builtin_ctzl(x);
190#elif defined(_WIN64)
191  unsigned long ret;  // NOLINT
192  _BitScanForward64(&ret, x);
193  return ret;
194#else
195  unsigned long ret;  // NOLINT
196  _BitScanForward(&ret, x);
197  return ret;
198#endif
199}
200
201static inline uptr RoundUpToPowerOfTwo(uptr size) {
202  CHECK(size);
203  if (IsPowerOfTwo(size)) return size;
204
205  unsigned long up;  // NOLINT
206#if !defined(_WIN32) || defined(__clang__)
207  up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(size);
208#elif defined(_WIN64)
209  _BitScanReverse64(&up, size);
210#else
211  _BitScanReverse(&up, size);
212#endif
213  CHECK(size < (1ULL << (up + 1)));
214  CHECK(size > (1ULL << up));
215  return 1UL << (up + 1);
216}
217
218
219}  // namespace __asan
220#endif  // ASAN_ALLOCATOR_H
221