blob: 803aa23927534e7b907475189af77c9ab84b2d2f [file] [log] [blame]
Kostya Serebryany1e172b42011-11-30 01:07:02 +00001//===-- 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
Kostya Serebryany8b0a7ce2012-12-10 13:52:55 +000021// 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
Kostya Serebryany1e172b42011-11-30 01:07:02 +000027namespace __asan {
28
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000029static const uptr kNumberOfSizeClasses = 255;
Kostya Serebryanycbab9112011-11-30 17:33:13 +000030struct AsanChunk;
Kostya Serebryany1e172b42011-11-30 01:07:02 +000031
Alexey Samsonov5c153fa2012-09-18 07:38:10 +000032class 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
Kostya Serebryany1e172b42011-11-30 01:07:02 +000052class AsanChunkFifoList {
53 public:
54 explicit AsanChunkFifoList(LinkerInitialized) { }
55 AsanChunkFifoList() { clear(); }
56 void Push(AsanChunk *n);
57 void PushList(AsanChunkFifoList *q);
58 AsanChunk *Pop();
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000059 uptr size() { return size_; }
Kostya Serebryany1e172b42011-11-30 01:07:02 +000060 void clear() {
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000061 first_ = last_ = 0;
Kostya Serebryany1e172b42011-11-30 01:07:02 +000062 size_ = 0;
63 }
64 private:
65 AsanChunk *first_;
66 AsanChunk *last_;
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000067 uptr size_;
Kostya Serebryany1e172b42011-11-30 01:07:02 +000068};
69
70struct AsanThreadLocalMallocStorage {
71 explicit AsanThreadLocalMallocStorage(LinkerInitialized x)
72 : quarantine_(x) { }
73 AsanThreadLocalMallocStorage() {
Alexey Samsonov09672ca2012-02-08 13:45:31 +000074 CHECK(REAL(memset));
75 REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage));
Kostya Serebryany1e172b42011-11-30 01:07:02 +000076 }
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 {
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000086 uptr magic; // Modified by the instrumented code.
87 uptr descr; // Modified by the instrumented code.
Kostya Serebryany1e172b42011-11-30 01:07:02 +000088 FakeFrame *next;
Kostya Serebryanyee392552012-05-31 15:02:07 +000089 u64 real_stack : 48;
90 u64 size_minus_one : 16;
Kostya Serebryany1e172b42011-11-30 01:07:02 +000091};
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) {}
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000129 void Init(uptr stack_size);
Kostya Serebryanyc4b34d92011-12-09 01:49:31 +0000130 void StopUsingFakeStack() { alive_ = false; }
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000131 void Cleanup();
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000132 uptr AllocateStack(uptr size, uptr real_stack);
133 static void OnFree(uptr ptr, uptr size, uptr real_stack);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000134 // Return the bottom of the maped region.
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000135 uptr AddrIsInFakeStack(uptr addr);
Alexander Potapenko60490e02012-02-21 08:45:41 +0000136 bool StackSize() { return stack_size_; }
Alexey Samsonov50926822012-08-30 14:22:21 +0000137
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000138 private:
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000139 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 =
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000143 kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
144
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000145 bool AddrIsInSizeClass(uptr addr, uptr size_class);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000146
147 // Each size class should be large enough to hold all frames.
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000148 uptr ClassMmapSize(uptr size_class);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000149
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000150 uptr ClassSize(uptr size_class) {
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000151 return 1UL << (size_class + kMinStackFrameSizeLog);
152 }
153
154 void DeallocateFrame(FakeFrame *fake_frame);
155
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000156 uptr ComputeSizeClass(uptr alloc_size);
157 void AllocateOneSizeClass(uptr size_class);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000158
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000159 uptr stack_size_;
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000160 bool alive_;
161
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000162 uptr allocated_size_classes_[kNumberOfSizeClasses];
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000163 FakeFrameFifo size_classes_[kNumberOfSizeClasses];
164 FakeFrameLifo call_stack_;
165};
166
Kostya Serebryanyc3390df2012-08-28 11:54:30 +0000167void *asan_memalign(uptr alignment, uptr size, StackTrace *stack);
168void asan_free(void *ptr, StackTrace *stack);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000169
Kostya Serebryanyc3390df2012-08-28 11:54:30 +0000170void *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);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000175
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000176int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
Kostya Serebryanyc3390df2012-08-28 11:54:30 +0000177 StackTrace *stack);
178uptr asan_malloc_usable_size(void *ptr, StackTrace *stack);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000179
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000180uptr asan_mz_size(const void *ptr);
Alexey Samsonov4fd95f12012-01-17 06:39:10 +0000181void asan_mz_force_lock();
182void asan_mz_force_unlock();
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000183
184} // namespace __asan
185#endif // ASAN_ALLOCATOR_H