1 //===-- asan_malloc_linux.cpp ---------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file is a part of AddressSanitizer, an address sanity checker.
11 // Linux-specific malloc interception.
12 // We simply define functions like malloc, free, realloc, etc.
13 // They will replace the corresponding libc functions automagically.
14 //===----------------------------------------------------------------------===//
16 #include "sanitizer_common/sanitizer_platform.h"
17 #if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \
18 SANITIZER_NETBSD || SANITIZER_SOLARIS
20 # include "asan_allocator.h"
21 # include "asan_interceptors.h"
22 # include "asan_internal.h"
23 # include "asan_stack.h"
24 # include "lsan/lsan_common.h"
25 # include "sanitizer_common/sanitizer_allocator_checks.h"
26 # include "sanitizer_common/sanitizer_allocator_dlsym.h"
27 # include "sanitizer_common/sanitizer_errno.h"
28 # include "sanitizer_common/sanitizer_tls_get_addr.h"
30 // ---------------------- Replacement functions ---------------- {{{1
31 using namespace __asan
;
33 struct DlsymAlloc
: public DlSymAllocator
<DlsymAlloc
> {
34 static bool UseImpl() { return asan_init_is_running
; }
35 static void OnAllocate(const void *ptr
, uptr size
) {
36 # if CAN_SANITIZE_LEAKS
37 // Suppress leaks from dlerror(). Previously dlsym hack on global array was
38 // used by leak sanitizer as a root region.
39 __lsan_register_root_region(ptr
, size
);
42 static void OnFree(const void *ptr
, uptr size
) {
43 # if CAN_SANITIZE_LEAKS
44 __lsan_unregister_root_region(ptr
, size
);
49 INTERCEPTOR(void, free
, void *ptr
) {
50 if (DlsymAlloc::PointerIsMine(ptr
))
51 return DlsymAlloc::Free(ptr
);
53 asan_free(ptr
, &stack
, FROM_MALLOC
);
56 #if SANITIZER_INTERCEPT_CFREE
57 INTERCEPTOR(void, cfree
, void *ptr
) {
58 if (DlsymAlloc::PointerIsMine(ptr
))
59 return DlsymAlloc::Free(ptr
);
61 asan_free(ptr
, &stack
, FROM_MALLOC
);
63 #endif // SANITIZER_INTERCEPT_CFREE
65 INTERCEPTOR(void*, malloc
, uptr size
) {
66 if (DlsymAlloc::Use())
67 return DlsymAlloc::Allocate(size
);
69 GET_STACK_TRACE_MALLOC
;
70 return asan_malloc(size
, &stack
);
73 INTERCEPTOR(void*, calloc
, uptr nmemb
, uptr size
) {
74 if (DlsymAlloc::Use())
75 return DlsymAlloc::Callocate(nmemb
, size
);
77 GET_STACK_TRACE_MALLOC
;
78 return asan_calloc(nmemb
, size
, &stack
);
81 INTERCEPTOR(void*, realloc
, void *ptr
, uptr size
) {
82 if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr
))
83 return DlsymAlloc::Realloc(ptr
, size
);
85 GET_STACK_TRACE_MALLOC
;
86 return asan_realloc(ptr
, size
, &stack
);
89 #if SANITIZER_INTERCEPT_REALLOCARRAY
90 INTERCEPTOR(void*, reallocarray
, void *ptr
, uptr nmemb
, uptr size
) {
92 GET_STACK_TRACE_MALLOC
;
93 return asan_reallocarray(ptr
, nmemb
, size
, &stack
);
95 #endif // SANITIZER_INTERCEPT_REALLOCARRAY
97 #if SANITIZER_INTERCEPT_MEMALIGN
98 INTERCEPTOR(void*, memalign
, uptr boundary
, uptr size
) {
99 GET_STACK_TRACE_MALLOC
;
100 return asan_memalign(boundary
, size
, &stack
, FROM_MALLOC
);
103 INTERCEPTOR(void*, __libc_memalign
, uptr boundary
, uptr size
) {
104 GET_STACK_TRACE_MALLOC
;
105 void *res
= asan_memalign(boundary
, size
, &stack
, FROM_MALLOC
);
106 DTLS_on_libc_memalign(res
, size
);
109 #endif // SANITIZER_INTERCEPT_MEMALIGN
111 #if SANITIZER_INTERCEPT_ALIGNED_ALLOC
112 INTERCEPTOR(void*, aligned_alloc
, uptr boundary
, uptr size
) {
113 GET_STACK_TRACE_MALLOC
;
114 return asan_aligned_alloc(boundary
, size
, &stack
);
116 #endif // SANITIZER_INTERCEPT_ALIGNED_ALLOC
118 INTERCEPTOR(uptr
, malloc_usable_size
, void *ptr
) {
119 GET_CURRENT_PC_BP_SP
;
121 return asan_malloc_usable_size(ptr
, pc
, bp
);
124 #if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
125 // We avoid including malloc.h for portability reasons.
126 // man mallinfo says the fields are "long", but the implementation uses int.
127 // It doesn't matter much -- we just need to make sure that the libc's mallinfo
129 struct fake_mallinfo
{
133 INTERCEPTOR(struct fake_mallinfo
, mallinfo
, void) {
134 struct fake_mallinfo res
;
135 REAL(memset
)(&res
, 0, sizeof(res
));
139 INTERCEPTOR(int, mallopt
, int cmd
, int value
) {
142 #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
144 INTERCEPTOR(int, posix_memalign
, void **memptr
, uptr alignment
, uptr size
) {
145 GET_STACK_TRACE_MALLOC
;
146 return asan_posix_memalign(memptr
, alignment
, size
, &stack
);
149 INTERCEPTOR(void*, valloc
, uptr size
) {
150 GET_STACK_TRACE_MALLOC
;
151 return asan_valloc(size
, &stack
);
154 #if SANITIZER_INTERCEPT_PVALLOC
155 INTERCEPTOR(void*, pvalloc
, uptr size
) {
156 GET_STACK_TRACE_MALLOC
;
157 return asan_pvalloc(size
, &stack
);
159 #endif // SANITIZER_INTERCEPT_PVALLOC
161 INTERCEPTOR(void, malloc_stats
, void) {
162 __asan_print_accumulated_stats();
165 #if SANITIZER_ANDROID
166 // Format of __libc_malloc_dispatch has changed in Android L.
167 // While we are moving towards a solution that does not depend on bionic
168 // internals, here is something to support both K* and L releases.
169 struct MallocDebugK
{
170 void *(*malloc
)(uptr bytes
);
171 void (*free
)(void *mem
);
172 void *(*calloc
)(uptr n_elements
, uptr elem_size
);
173 void *(*realloc
)(void *oldMem
, uptr bytes
);
174 void *(*memalign
)(uptr alignment
, uptr bytes
);
175 uptr (*malloc_usable_size
)(void *mem
);
178 struct MallocDebugL
{
179 void *(*calloc
)(uptr n_elements
, uptr elem_size
);
180 void (*free
)(void *mem
);
181 fake_mallinfo (*mallinfo
)(void);
182 void *(*malloc
)(uptr bytes
);
183 uptr (*malloc_usable_size
)(void *mem
);
184 void *(*memalign
)(uptr alignment
, uptr bytes
);
185 int (*posix_memalign
)(void **memptr
, uptr alignment
, uptr size
);
186 void* (*pvalloc
)(uptr size
);
187 void *(*realloc
)(void *oldMem
, uptr bytes
);
188 void* (*valloc
)(uptr size
);
191 ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k
= {
192 WRAP(malloc
), WRAP(free
), WRAP(calloc
),
193 WRAP(realloc
), WRAP(memalign
), WRAP(malloc_usable_size
)};
195 ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l
= {
196 WRAP(calloc
), WRAP(free
), WRAP(mallinfo
),
197 WRAP(malloc
), WRAP(malloc_usable_size
), WRAP(memalign
),
198 WRAP(posix_memalign
), WRAP(pvalloc
), WRAP(realloc
),
202 void ReplaceSystemMalloc() {
203 void **__libc_malloc_dispatch_p
=
204 (void **)AsanDlSymNext("__libc_malloc_dispatch");
205 if (__libc_malloc_dispatch_p
) {
206 // Decide on K vs L dispatch format by the presence of
207 // __libc_malloc_default_dispatch export in libc.
208 void *default_dispatch_p
= AsanDlSymNext("__libc_malloc_default_dispatch");
209 if (default_dispatch_p
)
210 *__libc_malloc_dispatch_p
= (void *)&asan_malloc_dispatch_k
;
212 *__libc_malloc_dispatch_p
= (void *)&asan_malloc_dispatch_l
;
215 } // namespace __asan
217 #else // SANITIZER_ANDROID
220 void ReplaceSystemMalloc() {
222 } // namespace __asan
223 #endif // SANITIZER_ANDROID
225 #endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX ||
226 // SANITIZER_NETBSD || SANITIZER_SOLARIS