1*7c3d14c8STreehugger Robot //===-- asan_malloc_linux.cc ----------------------------------------------===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot // The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // This file is a part of AddressSanitizer, an address sanity checker.
11*7c3d14c8STreehugger Robot //
12*7c3d14c8STreehugger Robot // Linux-specific malloc interception.
13*7c3d14c8STreehugger Robot // We simply define functions like malloc, free, realloc, etc.
14*7c3d14c8STreehugger Robot // They will replace the corresponding libc functions automagically.
15*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
16*7c3d14c8STreehugger Robot
17*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_platform.h"
18*7c3d14c8STreehugger Robot #if SANITIZER_FREEBSD || SANITIZER_LINUX
19*7c3d14c8STreehugger Robot
20*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_tls_get_addr.h"
21*7c3d14c8STreehugger Robot #include "asan_allocator.h"
22*7c3d14c8STreehugger Robot #include "asan_interceptors.h"
23*7c3d14c8STreehugger Robot #include "asan_internal.h"
24*7c3d14c8STreehugger Robot #include "asan_stack.h"
25*7c3d14c8STreehugger Robot
26*7c3d14c8STreehugger Robot // ---------------------- Replacement functions ---------------- {{{1
27*7c3d14c8STreehugger Robot using namespace __asan; // NOLINT
28*7c3d14c8STreehugger Robot
29*7c3d14c8STreehugger Robot static uptr allocated_for_dlsym;
30*7c3d14c8STreehugger Robot static const uptr kDlsymAllocPoolSize = 1024;
31*7c3d14c8STreehugger Robot static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize];
32*7c3d14c8STreehugger Robot
IsInDlsymAllocPool(const void * ptr)33*7c3d14c8STreehugger Robot static bool IsInDlsymAllocPool(const void *ptr) {
34*7c3d14c8STreehugger Robot uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
35*7c3d14c8STreehugger Robot return off < sizeof(alloc_memory_for_dlsym);
36*7c3d14c8STreehugger Robot }
37*7c3d14c8STreehugger Robot
AllocateFromLocalPool(uptr size_in_bytes)38*7c3d14c8STreehugger Robot static void *AllocateFromLocalPool(uptr size_in_bytes) {
39*7c3d14c8STreehugger Robot uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize;
40*7c3d14c8STreehugger Robot void *mem = (void*)&alloc_memory_for_dlsym[allocated_for_dlsym];
41*7c3d14c8STreehugger Robot allocated_for_dlsym += size_in_words;
42*7c3d14c8STreehugger Robot CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize);
43*7c3d14c8STreehugger Robot return mem;
44*7c3d14c8STreehugger Robot }
45*7c3d14c8STreehugger Robot
INTERCEPTOR(void,free,void * ptr)46*7c3d14c8STreehugger Robot INTERCEPTOR(void, free, void *ptr) {
47*7c3d14c8STreehugger Robot GET_STACK_TRACE_FREE;
48*7c3d14c8STreehugger Robot if (UNLIKELY(IsInDlsymAllocPool(ptr)))
49*7c3d14c8STreehugger Robot return;
50*7c3d14c8STreehugger Robot asan_free(ptr, &stack, FROM_MALLOC);
51*7c3d14c8STreehugger Robot }
52*7c3d14c8STreehugger Robot
INTERCEPTOR(void,cfree,void * ptr)53*7c3d14c8STreehugger Robot INTERCEPTOR(void, cfree, void *ptr) {
54*7c3d14c8STreehugger Robot GET_STACK_TRACE_FREE;
55*7c3d14c8STreehugger Robot if (UNLIKELY(IsInDlsymAllocPool(ptr)))
56*7c3d14c8STreehugger Robot return;
57*7c3d14c8STreehugger Robot asan_free(ptr, &stack, FROM_MALLOC);
58*7c3d14c8STreehugger Robot }
59*7c3d14c8STreehugger Robot
INTERCEPTOR(void *,malloc,uptr size)60*7c3d14c8STreehugger Robot INTERCEPTOR(void*, malloc, uptr size) {
61*7c3d14c8STreehugger Robot if (UNLIKELY(!asan_inited))
62*7c3d14c8STreehugger Robot // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym.
63*7c3d14c8STreehugger Robot return AllocateFromLocalPool(size);
64*7c3d14c8STreehugger Robot GET_STACK_TRACE_MALLOC;
65*7c3d14c8STreehugger Robot return asan_malloc(size, &stack);
66*7c3d14c8STreehugger Robot }
67*7c3d14c8STreehugger Robot
INTERCEPTOR(void *,calloc,uptr nmemb,uptr size)68*7c3d14c8STreehugger Robot INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
69*7c3d14c8STreehugger Robot if (UNLIKELY(!asan_inited))
70*7c3d14c8STreehugger Robot // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
71*7c3d14c8STreehugger Robot return AllocateFromLocalPool(nmemb * size);
72*7c3d14c8STreehugger Robot GET_STACK_TRACE_MALLOC;
73*7c3d14c8STreehugger Robot return asan_calloc(nmemb, size, &stack);
74*7c3d14c8STreehugger Robot }
75*7c3d14c8STreehugger Robot
INTERCEPTOR(void *,realloc,void * ptr,uptr size)76*7c3d14c8STreehugger Robot INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
77*7c3d14c8STreehugger Robot GET_STACK_TRACE_MALLOC;
78*7c3d14c8STreehugger Robot if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
79*7c3d14c8STreehugger Robot uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
80*7c3d14c8STreehugger Robot uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
81*7c3d14c8STreehugger Robot void *new_ptr = asan_malloc(size, &stack);
82*7c3d14c8STreehugger Robot internal_memcpy(new_ptr, ptr, copy_size);
83*7c3d14c8STreehugger Robot return new_ptr;
84*7c3d14c8STreehugger Robot }
85*7c3d14c8STreehugger Robot return asan_realloc(ptr, size, &stack);
86*7c3d14c8STreehugger Robot }
87*7c3d14c8STreehugger Robot
INTERCEPTOR(void *,memalign,uptr boundary,uptr size)88*7c3d14c8STreehugger Robot INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
89*7c3d14c8STreehugger Robot GET_STACK_TRACE_MALLOC;
90*7c3d14c8STreehugger Robot return asan_memalign(boundary, size, &stack, FROM_MALLOC);
91*7c3d14c8STreehugger Robot }
92*7c3d14c8STreehugger Robot
INTERCEPTOR(void *,aligned_alloc,uptr boundary,uptr size)93*7c3d14c8STreehugger Robot INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
94*7c3d14c8STreehugger Robot GET_STACK_TRACE_MALLOC;
95*7c3d14c8STreehugger Robot return asan_memalign(boundary, size, &stack, FROM_MALLOC);
96*7c3d14c8STreehugger Robot }
97*7c3d14c8STreehugger Robot
INTERCEPTOR(void *,__libc_memalign,uptr boundary,uptr size)98*7c3d14c8STreehugger Robot INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
99*7c3d14c8STreehugger Robot GET_STACK_TRACE_MALLOC;
100*7c3d14c8STreehugger Robot void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC);
101*7c3d14c8STreehugger Robot DTLS_on_libc_memalign(res, size);
102*7c3d14c8STreehugger Robot return res;
103*7c3d14c8STreehugger Robot }
104*7c3d14c8STreehugger Robot
INTERCEPTOR(uptr,malloc_usable_size,void * ptr)105*7c3d14c8STreehugger Robot INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
106*7c3d14c8STreehugger Robot GET_CURRENT_PC_BP_SP;
107*7c3d14c8STreehugger Robot (void)sp;
108*7c3d14c8STreehugger Robot return asan_malloc_usable_size(ptr, pc, bp);
109*7c3d14c8STreehugger Robot }
110*7c3d14c8STreehugger Robot
111*7c3d14c8STreehugger Robot // We avoid including malloc.h for portability reasons.
112*7c3d14c8STreehugger Robot // man mallinfo says the fields are "long", but the implementation uses int.
113*7c3d14c8STreehugger Robot // It doesn't matter much -- we just need to make sure that the libc's mallinfo
114*7c3d14c8STreehugger Robot // is not called.
115*7c3d14c8STreehugger Robot struct fake_mallinfo {
116*7c3d14c8STreehugger Robot int x[10];
117*7c3d14c8STreehugger Robot };
118*7c3d14c8STreehugger Robot
INTERCEPTOR(struct fake_mallinfo,mallinfo,void)119*7c3d14c8STreehugger Robot INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
120*7c3d14c8STreehugger Robot struct fake_mallinfo res;
121*7c3d14c8STreehugger Robot REAL(memset)(&res, 0, sizeof(res));
122*7c3d14c8STreehugger Robot return res;
123*7c3d14c8STreehugger Robot }
124*7c3d14c8STreehugger Robot
INTERCEPTOR(int,mallopt,int cmd,int value)125*7c3d14c8STreehugger Robot INTERCEPTOR(int, mallopt, int cmd, int value) {
126*7c3d14c8STreehugger Robot return -1;
127*7c3d14c8STreehugger Robot }
128*7c3d14c8STreehugger Robot
INTERCEPTOR(int,posix_memalign,void ** memptr,uptr alignment,uptr size)129*7c3d14c8STreehugger Robot INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
130*7c3d14c8STreehugger Robot GET_STACK_TRACE_MALLOC;
131*7c3d14c8STreehugger Robot // Printf("posix_memalign: %zx %zu\n", alignment, size);
132*7c3d14c8STreehugger Robot return asan_posix_memalign(memptr, alignment, size, &stack);
133*7c3d14c8STreehugger Robot }
134*7c3d14c8STreehugger Robot
INTERCEPTOR(void *,valloc,uptr size)135*7c3d14c8STreehugger Robot INTERCEPTOR(void*, valloc, uptr size) {
136*7c3d14c8STreehugger Robot GET_STACK_TRACE_MALLOC;
137*7c3d14c8STreehugger Robot return asan_valloc(size, &stack);
138*7c3d14c8STreehugger Robot }
139*7c3d14c8STreehugger Robot
INTERCEPTOR(void *,pvalloc,uptr size)140*7c3d14c8STreehugger Robot INTERCEPTOR(void*, pvalloc, uptr size) {
141*7c3d14c8STreehugger Robot GET_STACK_TRACE_MALLOC;
142*7c3d14c8STreehugger Robot return asan_pvalloc(size, &stack);
143*7c3d14c8STreehugger Robot }
144*7c3d14c8STreehugger Robot
INTERCEPTOR(void,malloc_stats,void)145*7c3d14c8STreehugger Robot INTERCEPTOR(void, malloc_stats, void) {
146*7c3d14c8STreehugger Robot __asan_print_accumulated_stats();
147*7c3d14c8STreehugger Robot }
148*7c3d14c8STreehugger Robot
149*7c3d14c8STreehugger Robot #if SANITIZER_ANDROID
150*7c3d14c8STreehugger Robot // Format of __libc_malloc_dispatch has changed in Android L.
151*7c3d14c8STreehugger Robot // While we are moving towards a solution that does not depend on bionic
152*7c3d14c8STreehugger Robot // internals, here is something to support both K* and L releases.
153*7c3d14c8STreehugger Robot struct MallocDebugK {
154*7c3d14c8STreehugger Robot void *(*malloc)(uptr bytes);
155*7c3d14c8STreehugger Robot void (*free)(void *mem);
156*7c3d14c8STreehugger Robot void *(*calloc)(uptr n_elements, uptr elem_size);
157*7c3d14c8STreehugger Robot void *(*realloc)(void *oldMem, uptr bytes);
158*7c3d14c8STreehugger Robot void *(*memalign)(uptr alignment, uptr bytes);
159*7c3d14c8STreehugger Robot uptr (*malloc_usable_size)(void *mem);
160*7c3d14c8STreehugger Robot };
161*7c3d14c8STreehugger Robot
162*7c3d14c8STreehugger Robot struct MallocDebugL {
163*7c3d14c8STreehugger Robot void *(*calloc)(uptr n_elements, uptr elem_size);
164*7c3d14c8STreehugger Robot void (*free)(void *mem);
165*7c3d14c8STreehugger Robot fake_mallinfo (*mallinfo)(void);
166*7c3d14c8STreehugger Robot void *(*malloc)(uptr bytes);
167*7c3d14c8STreehugger Robot uptr (*malloc_usable_size)(void *mem);
168*7c3d14c8STreehugger Robot void *(*memalign)(uptr alignment, uptr bytes);
169*7c3d14c8STreehugger Robot int (*posix_memalign)(void **memptr, uptr alignment, uptr size);
170*7c3d14c8STreehugger Robot void* (*pvalloc)(uptr size);
171*7c3d14c8STreehugger Robot void *(*realloc)(void *oldMem, uptr bytes);
172*7c3d14c8STreehugger Robot void* (*valloc)(uptr size);
173*7c3d14c8STreehugger Robot };
174*7c3d14c8STreehugger Robot
175*7c3d14c8STreehugger Robot ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = {
176*7c3d14c8STreehugger Robot WRAP(malloc), WRAP(free), WRAP(calloc),
177*7c3d14c8STreehugger Robot WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};
178*7c3d14c8STreehugger Robot
179*7c3d14c8STreehugger Robot ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = {
180*7c3d14c8STreehugger Robot WRAP(calloc), WRAP(free), WRAP(mallinfo),
181*7c3d14c8STreehugger Robot WRAP(malloc), WRAP(malloc_usable_size), WRAP(memalign),
182*7c3d14c8STreehugger Robot WRAP(posix_memalign), WRAP(pvalloc), WRAP(realloc),
183*7c3d14c8STreehugger Robot WRAP(valloc)};
184*7c3d14c8STreehugger Robot
185*7c3d14c8STreehugger Robot namespace __asan {
ReplaceSystemMalloc()186*7c3d14c8STreehugger Robot void ReplaceSystemMalloc() {
187*7c3d14c8STreehugger Robot void **__libc_malloc_dispatch_p =
188*7c3d14c8STreehugger Robot (void **)AsanDlSymNext("__libc_malloc_dispatch");
189*7c3d14c8STreehugger Robot if (__libc_malloc_dispatch_p) {
190*7c3d14c8STreehugger Robot // Decide on K vs L dispatch format by the presence of
191*7c3d14c8STreehugger Robot // __libc_malloc_default_dispatch export in libc.
192*7c3d14c8STreehugger Robot void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch");
193*7c3d14c8STreehugger Robot if (default_dispatch_p)
194*7c3d14c8STreehugger Robot *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k;
195*7c3d14c8STreehugger Robot else
196*7c3d14c8STreehugger Robot *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l;
197*7c3d14c8STreehugger Robot }
198*7c3d14c8STreehugger Robot }
199*7c3d14c8STreehugger Robot } // namespace __asan
200*7c3d14c8STreehugger Robot
201*7c3d14c8STreehugger Robot #else // SANITIZER_ANDROID
202*7c3d14c8STreehugger Robot
203*7c3d14c8STreehugger Robot namespace __asan {
ReplaceSystemMalloc()204*7c3d14c8STreehugger Robot void ReplaceSystemMalloc() {
205*7c3d14c8STreehugger Robot }
206*7c3d14c8STreehugger Robot } // namespace __asan
207*7c3d14c8STreehugger Robot #endif // SANITIZER_ANDROID
208*7c3d14c8STreehugger Robot
209*7c3d14c8STreehugger Robot #endif // SANITIZER_FREEBSD || SANITIZER_LINUX
210