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) || ASAN_MAC || ASAN_WINDOWS
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;
43 void InitializeAllocator();
47 explicit AsanChunkView(AsanChunk
*chunk
) : chunk_(chunk
) {}
48 bool IsValid() { return chunk_
!= 0; }
49 uptr
Beg(); // first byte of user memory.
50 uptr
End(); // last byte of user memory.
51 uptr
UsedSize(); // size requested by the user.
54 void GetAllocStack(StackTrace
*stack
);
55 void GetFreeStack(StackTrace
*stack
);
56 bool AddrIsInside(uptr addr
, uptr access_size
, sptr
*offset
) {
57 if (addr
>= Beg() && (addr
+ access_size
) <= End()) {
58 *offset
= addr
- Beg();
63 bool AddrIsAtLeft(uptr addr
, uptr access_size
, sptr
*offset
) {
66 *offset
= Beg() - addr
;
71 bool AddrIsAtRight(uptr addr
, uptr access_size
, sptr
*offset
) {
72 if (addr
+ access_size
> End()) {
73 *offset
= addr
- End();
80 AsanChunk
*const chunk_
;
83 AsanChunkView
FindHeapChunkByAddress(uptr address
);
85 // List of AsanChunks with total size.
86 class AsanChunkFifoList
: public IntrusiveList
<AsanChunk
> {
88 explicit AsanChunkFifoList(LinkerInitialized
) { }
89 AsanChunkFifoList() { clear(); }
90 void Push(AsanChunk
*n
);
91 void PushList(AsanChunkFifoList
*q
);
93 uptr
size() { return size_
; }
95 IntrusiveList
<AsanChunk
>::clear();
102 struct AsanThreadLocalMallocStorage
{
103 explicit AsanThreadLocalMallocStorage(LinkerInitialized x
)
104 #if ASAN_ALLOCATOR_VERSION == 1
108 AsanThreadLocalMallocStorage() {
110 REAL(memset
)(this, 0, sizeof(AsanThreadLocalMallocStorage
));
113 #if ASAN_ALLOCATOR_VERSION == 1
114 AsanChunkFifoList quarantine_
;
115 AsanChunk
*free_lists_
[kNumberOfSizeClasses
];
117 uptr quarantine_cache
[16];
118 uptr allocator2_cache
[96 * (512 * 8 + 16)]; // Opaque.
123 // Fake stack frame contains local variables of one function.
124 // This struct should fit into a stack redzone (32 bytes).
126 uptr magic
; // Modified by the instrumented code.
127 uptr descr
; // Modified by the instrumented code.
130 u64 size_minus_one
: 16;
133 struct FakeFrameFifo
{
135 void FifoPush(FakeFrame
*node
);
136 FakeFrame
*FifoPop();
138 FakeFrame
*first_
, *last_
;
141 class FakeFrameLifo
{
143 void LifoPush(FakeFrame
*node
) {
151 FakeFrame
*top() { return top_
; }
156 // For each thread we create a fake stack and place stack objects on this fake
157 // stack instead of the real stack. The fake stack is not really a stack but
158 // a fast malloc-like allocator so that when a function exits the fake stack
159 // is not poped but remains there for quite some time until gets used again.
160 // So, we poison the objects on the fake stack when function returns.
161 // It helps us find use-after-return bugs.
162 // We can not rely on __asan_stack_free being called on every function exit,
163 // so we maintain a lifo list of all current fake frames and update it on every
164 // call to __asan_stack_malloc.
168 explicit FakeStack(LinkerInitialized
) {}
169 void Init(uptr stack_size
);
170 void StopUsingFakeStack() { alive_
= false; }
172 uptr
AllocateStack(uptr size
, uptr real_stack
);
173 static void OnFree(uptr ptr
, uptr size
, uptr real_stack
);
174 // Return the bottom of the maped region.
175 uptr
AddrIsInFakeStack(uptr addr
);
176 bool StackSize() { return stack_size_
; }
179 static const uptr kMinStackFrameSizeLog
= 9; // Min frame is 512B.
180 static const uptr kMaxStackFrameSizeLog
= 16; // Max stack frame is 64K.
181 static const uptr kMaxStackMallocSize
= 1 << kMaxStackFrameSizeLog
;
182 static const uptr kNumberOfSizeClasses
=
183 kMaxStackFrameSizeLog
- kMinStackFrameSizeLog
+ 1;
185 bool AddrIsInSizeClass(uptr addr
, uptr size_class
);
187 // Each size class should be large enough to hold all frames.
188 uptr
ClassMmapSize(uptr size_class
);
190 uptr
ClassSize(uptr size_class
) {
191 return 1UL << (size_class
+ kMinStackFrameSizeLog
);
194 void DeallocateFrame(FakeFrame
*fake_frame
);
196 uptr
ComputeSizeClass(uptr alloc_size
);
197 void AllocateOneSizeClass(uptr size_class
);
202 uptr allocated_size_classes_
[kNumberOfSizeClasses
];
203 FakeFrameFifo size_classes_
[kNumberOfSizeClasses
];
204 FakeFrameLifo call_stack_
;
207 void *asan_memalign(uptr alignment
, uptr size
, StackTrace
*stack
,
208 AllocType alloc_type
);
209 void asan_free(void *ptr
, StackTrace
*stack
, AllocType alloc_type
);
211 void *asan_malloc(uptr size
, StackTrace
*stack
);
212 void *asan_calloc(uptr nmemb
, uptr size
, StackTrace
*stack
);
213 void *asan_realloc(void *p
, uptr size
, StackTrace
*stack
);
214 void *asan_valloc(uptr size
, StackTrace
*stack
);
215 void *asan_pvalloc(uptr size
, StackTrace
*stack
);
217 int asan_posix_memalign(void **memptr
, uptr alignment
, uptr size
,
219 uptr
asan_malloc_usable_size(void *ptr
, StackTrace
*stack
);
221 uptr
asan_mz_size(const void *ptr
);
222 void asan_mz_force_lock();
223 void asan_mz_force_unlock();
225 void PrintInternalAllocatorStats();
227 } // namespace __asan
228 #endif // ASAN_ALLOCATOR_H