1 //===-- asan_allocator.h ----------------------------------------*- C++ -*-===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of AddressSanitizer, an address sanity checker.
10 // ASan-private header for asan_allocator.cc.
11 //===----------------------------------------------------------------------===//
13 #ifndef ASAN_ALLOCATOR_H
14 #define ASAN_ALLOCATOR_H
16 #include "asan_internal.h"
17 #include "asan_interceptors.h"
18 #include "sanitizer_common/sanitizer_list.h"
20 // We are in the process of transitioning from the old allocator (version 1)
21 // to a new one (version 2). The change is quite intrusive so both allocators
22 // will co-exist in the source base for a while. The actual allocator is chosen
23 // at build time by redefining this macro.
24 #ifndef ASAN_ALLOCATOR_VERSION
25 # if ASAN_LINUX && !ASAN_ANDROID
26 # define ASAN_ALLOCATOR_VERSION 2
28 # define ASAN_ALLOCATOR_VERSION 1
30 #endif // ASAN_ALLOCATOR_VERSION
35 FROM_MALLOC
= 1, // Memory block came from malloc, calloc, realloc, etc.
36 FROM_NEW
= 2, // Memory block came from operator new.
37 FROM_NEW_BR
= 3 // Memory block came from operator new [ ]
40 static const uptr kNumberOfSizeClasses
= 255;
45 explicit AsanChunkView(AsanChunk
*chunk
) : chunk_(chunk
) {}
46 bool IsValid() { return chunk_
!= 0; }
47 uptr
Beg(); // first byte of user memory.
48 uptr
End(); // last byte of user memory.
49 uptr
UsedSize(); // size requested by the user.
52 void GetAllocStack(StackTrace
*stack
);
53 void GetFreeStack(StackTrace
*stack
);
54 bool AddrIsInside(uptr addr
, uptr access_size
, uptr
*offset
) {
55 if (addr
>= Beg() && (addr
+ access_size
) <= End()) {
56 *offset
= addr
- Beg();
61 bool AddrIsAtLeft(uptr addr
, uptr access_size
, uptr
*offset
) {
64 *offset
= Beg() - addr
;
69 bool AddrIsAtRight(uptr addr
, uptr access_size
, uptr
*offset
) {
70 if (addr
+ access_size
>= End()) {
74 *offset
= addr
- End();
81 AsanChunk
*const chunk_
;
84 AsanChunkView
FindHeapChunkByAddress(uptr address
);
86 // List of AsanChunks with total size.
87 class AsanChunkFifoList
: public IntrusiveList
<AsanChunk
> {
89 explicit AsanChunkFifoList(LinkerInitialized
) { }
90 AsanChunkFifoList() { clear(); }
91 void Push(AsanChunk
*n
);
92 void PushList(AsanChunkFifoList
*q
);
94 uptr
size() { return size_
; }
96 IntrusiveList
<AsanChunk
>::clear();
103 struct AsanThreadLocalMallocStorage
{
104 explicit AsanThreadLocalMallocStorage(LinkerInitialized x
)
105 #if ASAN_ALLOCATOR_VERSION == 1
109 AsanThreadLocalMallocStorage() {
111 REAL(memset
)(this, 0, sizeof(AsanThreadLocalMallocStorage
));
114 #if ASAN_ALLOCATOR_VERSION == 1
115 AsanChunkFifoList quarantine_
;
116 AsanChunk
*free_lists_
[kNumberOfSizeClasses
];
118 uptr quarantine_cache
[16];
119 uptr allocator2_cache
[96 * (512 * 8 + 16)]; // Opaque.
124 // Fake stack frame contains local variables of one function.
125 // This struct should fit into a stack redzone (32 bytes).
127 uptr magic
; // Modified by the instrumented code.
128 uptr descr
; // Modified by the instrumented code.
131 u64 size_minus_one
: 16;
134 struct FakeFrameFifo
{
136 void FifoPush(FakeFrame
*node
);
137 FakeFrame
*FifoPop();
139 FakeFrame
*first_
, *last_
;
142 class FakeFrameLifo
{
144 void LifoPush(FakeFrame
*node
) {
152 FakeFrame
*top() { return top_
; }
157 // For each thread we create a fake stack and place stack objects on this fake
158 // stack instead of the real stack. The fake stack is not really a stack but
159 // a fast malloc-like allocator so that when a function exits the fake stack
160 // is not poped but remains there for quite some time until gets used again.
161 // So, we poison the objects on the fake stack when function returns.
162 // It helps us find use-after-return bugs.
163 // We can not rely on __asan_stack_free being called on every function exit,
164 // so we maintain a lifo list of all current fake frames and update it on every
165 // call to __asan_stack_malloc.
169 explicit FakeStack(LinkerInitialized
) {}
170 void Init(uptr stack_size
);
171 void StopUsingFakeStack() { alive_
= false; }
173 uptr
AllocateStack(uptr size
, uptr real_stack
);
174 static void OnFree(uptr ptr
, uptr size
, uptr real_stack
);
175 // Return the bottom of the maped region.
176 uptr
AddrIsInFakeStack(uptr addr
);
177 bool StackSize() { return stack_size_
; }
180 static const uptr kMinStackFrameSizeLog
= 9; // Min frame is 512B.
181 static const uptr kMaxStackFrameSizeLog
= 16; // Max stack frame is 64K.
182 static const uptr kMaxStackMallocSize
= 1 << kMaxStackFrameSizeLog
;
183 static const uptr kNumberOfSizeClasses
=
184 kMaxStackFrameSizeLog
- kMinStackFrameSizeLog
+ 1;
186 bool AddrIsInSizeClass(uptr addr
, uptr size_class
);
188 // Each size class should be large enough to hold all frames.
189 uptr
ClassMmapSize(uptr size_class
);
191 uptr
ClassSize(uptr size_class
) {
192 return 1UL << (size_class
+ kMinStackFrameSizeLog
);
195 void DeallocateFrame(FakeFrame
*fake_frame
);
197 uptr
ComputeSizeClass(uptr alloc_size
);
198 void AllocateOneSizeClass(uptr size_class
);
203 uptr allocated_size_classes_
[kNumberOfSizeClasses
];
204 FakeFrameFifo size_classes_
[kNumberOfSizeClasses
];
205 FakeFrameLifo call_stack_
;
208 void *asan_memalign(uptr alignment
, uptr size
, StackTrace
*stack
,
209 AllocType alloc_type
);
210 void asan_free(void *ptr
, StackTrace
*stack
, AllocType alloc_type
);
212 void *asan_malloc(uptr size
, StackTrace
*stack
);
213 void *asan_calloc(uptr nmemb
, uptr size
, StackTrace
*stack
);
214 void *asan_realloc(void *p
, uptr size
, StackTrace
*stack
);
215 void *asan_valloc(uptr size
, StackTrace
*stack
);
216 void *asan_pvalloc(uptr size
, StackTrace
*stack
);
218 int asan_posix_memalign(void **memptr
, uptr alignment
, uptr size
,
220 uptr
asan_malloc_usable_size(void *ptr
, StackTrace
*stack
);
222 uptr
asan_mz_size(const void *ptr
);
223 void asan_mz_force_lock();
224 void asan_mz_force_unlock();
226 void PrintInternalAllocatorStats();
228 // Log2 and RoundUpToPowerOfTwo should be inlined for performance.
229 #if defined(_WIN32) && !defined(__clang__)
231 unsigned char _BitScanForward(unsigned long *index
, unsigned long mask
); // NOLINT
232 unsigned char _BitScanReverse(unsigned long *index
, unsigned long mask
); // NOLINT
234 unsigned char _BitScanForward64(unsigned long *index
, unsigned __int64 mask
); // NOLINT
235 unsigned char _BitScanReverse64(unsigned long *index
, unsigned __int64 mask
); // NOLINT
240 static inline uptr
Log2(uptr x
) {
241 CHECK(IsPowerOfTwo(x
));
242 #if !defined(_WIN32) || defined(__clang__)
243 return __builtin_ctzl(x
);
244 #elif defined(_WIN64)
245 unsigned long ret
; // NOLINT
246 _BitScanForward64(&ret
, x
);
249 unsigned long ret
; // NOLINT
250 _BitScanForward(&ret
, x
);
255 static inline uptr
RoundUpToPowerOfTwo(uptr size
) {
257 if (IsPowerOfTwo(size
)) return size
;
259 unsigned long up
; // NOLINT
260 #if !defined(_WIN32) || defined(__clang__)
261 up
= SANITIZER_WORDSIZE
- 1 - __builtin_clzl(size
);
262 #elif defined(_WIN64)
263 _BitScanReverse64(&up
, size
);
265 _BitScanReverse(&up
, size
);
267 CHECK(size
< (1ULL << (up
+ 1)));
268 CHECK(size
> (1ULL << up
));
269 return 1UL << (up
+ 1);
273 } // namespace __asan
274 #endif // ASAN_ALLOCATOR_H