1//===-- asan_malloc_linux.cpp ---------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8//
9// This file is a part of AddressSanitizer, an address sanity checker.
10//
11// Linux-specific (and Unix/Unix-like) malloc interception.
12// We simply define functions like malloc, free, realloc, etc.
13// They will replace the corresponding libc functions automagically.
14//===----------------------------------------------------------------------===//
15
16#include "sanitizer_common/sanitizer_platform.h"
17#if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \
18 SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_HAIKU || SANITIZER_AIX
19
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
29// ---------------------- Replacement functions ---------------- {{{1
30using namespace __asan;
31
32struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
33 static bool UseImpl() { return !TryAsanInitFromRtl(); }
34 static void OnAllocate(const void* ptr, uptr size) {
35# if CAN_SANITIZE_LEAKS
36 // Suppress leaks from dlerror(). Previously dlsym hack on global array was
37 // used by leak sanitizer as a root region.
38 __lsan_register_root_region(p: ptr, size);
39# endif
40 }
41 static void OnFree(const void* ptr, uptr size) {
42# if CAN_SANITIZE_LEAKS
43 __lsan_unregister_root_region(p: ptr, size);
44# endif
45 }
46};
47
48INTERCEPTOR(void, free, void* ptr) {
49 if (DlsymAlloc::PointerIsMine(ptr))
50 return DlsymAlloc::Free(ptr);
51 GET_STACK_TRACE_FREE;
52 asan_free(ptr, stack: &stack);
53}
54
55# if SANITIZER_INTERCEPT_CFREE
56INTERCEPTOR(void, cfree, void* ptr) {
57 if (DlsymAlloc::PointerIsMine(ptr))
58 return DlsymAlloc::Free(ptr);
59 GET_STACK_TRACE_FREE;
60 asan_free(ptr, stack: &stack);
61}
62# endif // SANITIZER_INTERCEPT_CFREE
63
64# if SANITIZER_INTERCEPT_FREE_SIZED
65INTERCEPTOR(void, free_sized, void* ptr, uptr size) {
66 if (UNLIKELY(!ptr))
67 return;
68 if (DlsymAlloc::PointerIsMine(ptr))
69 return DlsymAlloc::Free(ptr);
70 GET_STACK_TRACE_FREE;
71 asan_free_sized(ptr, size, stack: &stack);
72}
73# endif // SANITIZER_INTERCEPT_FREE_SIZED
74
75# if SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED
76INTERCEPTOR(void, free_aligned_sized, void* ptr, uptr alignment, uptr size) {
77 if (UNLIKELY(!ptr))
78 return;
79 if (DlsymAlloc::PointerIsMine(ptr))
80 return DlsymAlloc::Free(ptr);
81 GET_STACK_TRACE_FREE;
82 asan_free_aligned_sized(ptr, alignment, size, stack: &stack);
83}
84# endif // SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED
85
86# if SANITIZER_AIX
87// Unlike malloc, vec_malloc must return memory aligned to 16 bytes.
88INTERCEPTOR(void*, vec_malloc, uptr size) {
89 if (DlsymAlloc::Use())
90 return DlsymAlloc::Allocate(size, 16);
91 GET_STACK_TRACE_MALLOC;
92 return asan_vec_malloc(size, &stack);
93}
94
95// __linux_vec_malloc is the XL compiler internal symbol emitted instead of
96// vec_malloc.
97INTERCEPTOR(void*, __linux_vec_malloc, uptr size) {
98 if (DlsymAlloc::Use())
99 return DlsymAlloc::Allocate(size, 16);
100 GET_STACK_TRACE_MALLOC;
101 return asan_vec_malloc(size, &stack);
102}
103
104// Unlike calloc, vec_calloc must return memory aligned to 16 bytes.
105INTERCEPTOR(void*, vec_calloc, uptr nmemb, uptr size) {
106 if (DlsymAlloc::Use())
107 return DlsymAlloc::Callocate(nmemb, size, 16);
108 GET_STACK_TRACE_MALLOC;
109 return asan_vec_calloc(nmemb, size, &stack);
110}
111
112// __linux_vec_calloc is the XL compiler internal symbol emitted instead of
113// vec_calloc.
114INTERCEPTOR(void*, __linux_vec_calloc, uptr nmemb, uptr size) {
115 if (DlsymAlloc::Use())
116 return DlsymAlloc::Callocate(nmemb, size, 16);
117 GET_STACK_TRACE_MALLOC;
118 return asan_vec_calloc(nmemb, size, &stack);
119}
120# endif
121
122// TODO: Fix malloc/calloc interceptors to return 16-byte alignment with AIX on
123// PASE.
124INTERCEPTOR(void*, malloc, uptr size) {
125 if (DlsymAlloc::Use())
126 return DlsymAlloc::Allocate(size_in_bytes: size);
127 GET_STACK_TRACE_MALLOC;
128 return asan_malloc(size, stack: &stack);
129}
130
131INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
132 if (DlsymAlloc::Use())
133 return DlsymAlloc::Callocate(nmemb, size);
134 GET_STACK_TRACE_MALLOC;
135 return asan_calloc(nmemb, size, stack: &stack);
136}
137
138// TODO: AIX needs a method to ensure 16-byte alignment if the incoming
139// pointer was allocated with a 16-byte alignment requirement (or perhaps
140// merely if it happens to have 16-byte alignment).
141INTERCEPTOR(void*, realloc, void* ptr, uptr size) {
142 if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
143 return DlsymAlloc::Realloc(ptr, new_size: size);
144 GET_STACK_TRACE_MALLOC;
145 return asan_realloc(p: ptr, size, stack: &stack);
146}
147
148# if SANITIZER_AIX
149// __linux_realloc is the XL compiler internal symbol emitted instead of
150// realloc.
151INTERCEPTOR(void*, __linux_realloc, void* ptr, uptr size) {
152 if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
153 return DlsymAlloc::Realloc(ptr, size, kWordSize);
154 GET_STACK_TRACE_MALLOC;
155 return asan_realloc(ptr, size, &stack);
156}
157# endif
158
159# if SANITIZER_INTERCEPT_REALLOCARRAY
160INTERCEPTOR(void*, reallocarray, void* ptr, uptr nmemb, uptr size) {
161 AsanInitFromRtl();
162 GET_STACK_TRACE_MALLOC;
163 return asan_reallocarray(p: ptr, nmemb, size, stack: &stack);
164}
165# endif // SANITIZER_INTERCEPT_REALLOCARRAY
166
167# if SANITIZER_INTERCEPT_MEMALIGN
168INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
169 GET_STACK_TRACE_MALLOC;
170 return asan_memalign(alignment: boundary, size, stack: &stack);
171}
172
173INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
174 GET_STACK_TRACE_MALLOC;
175 return asan_memalign(alignment: boundary, size, stack: &stack);
176}
177# endif // SANITIZER_INTERCEPT_MEMALIGN
178
179# if SANITIZER_INTERCEPT_ALIGNED_ALLOC
180INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
181 GET_STACK_TRACE_MALLOC;
182 return asan_aligned_alloc(alignment: boundary, size, stack: &stack);
183}
184# endif // SANITIZER_INTERCEPT_ALIGNED_ALLOC
185
186INTERCEPTOR(uptr, malloc_usable_size, void* ptr) {
187 GET_CURRENT_PC_BP_SP;
188 (void)sp;
189 return asan_malloc_usable_size(ptr, pc, bp);
190}
191
192# if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
193// We avoid including malloc.h for portability reasons.
194// man mallinfo says the fields are "long", but the implementation uses int.
195// It doesn't matter much -- we just need to make sure that the libc's mallinfo
196// is not called.
197struct fake_mallinfo {
198 int x[10];
199};
200
201INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
202 struct fake_mallinfo res;
203 REAL(memset)(&res, 0, sizeof(res));
204 return res;
205}
206
207INTERCEPTOR(int, mallopt, int cmd, int value) { return 0; }
208# endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
209
210INTERCEPTOR(int, posix_memalign, void** memptr, uptr alignment, uptr size) {
211 GET_STACK_TRACE_MALLOC;
212 return asan_posix_memalign(memptr, alignment, size, stack: &stack);
213}
214
215INTERCEPTOR(void*, valloc, uptr size) {
216 GET_STACK_TRACE_MALLOC;
217 return asan_valloc(size, stack: &stack);
218}
219
220# if SANITIZER_INTERCEPT_PVALLOC
221INTERCEPTOR(void*, pvalloc, uptr size) {
222 GET_STACK_TRACE_MALLOC;
223 return asan_pvalloc(size, stack: &stack);
224}
225# endif // SANITIZER_INTERCEPT_PVALLOC
226
227INTERCEPTOR(void, malloc_stats, void) { __asan_print_accumulated_stats(); }
228
229# if SANITIZER_ANDROID
230// Format of __libc_malloc_dispatch has changed in Android L.
231// While we are moving towards a solution that does not depend on bionic
232// internals, here is something to support both K* and L releases.
233struct MallocDebugK {
234 void* (*malloc)(uptr bytes);
235 void (*free)(void* mem);
236 void* (*calloc)(uptr n_elements, uptr elem_size);
237 void* (*realloc)(void* oldMem, uptr bytes);
238 void* (*memalign)(uptr alignment, uptr bytes);
239 uptr (*malloc_usable_size)(void* mem);
240};
241
242struct MallocDebugL {
243 void* (*calloc)(uptr n_elements, uptr elem_size);
244 void (*free)(void* mem);
245 fake_mallinfo (*mallinfo)(void);
246 void* (*malloc)(uptr bytes);
247 uptr (*malloc_usable_size)(void* mem);
248 void* (*memalign)(uptr alignment, uptr bytes);
249 int (*posix_memalign)(void** memptr, uptr alignment, uptr size);
250 void* (*pvalloc)(uptr size);
251 void* (*realloc)(void* oldMem, uptr bytes);
252 void* (*valloc)(uptr size);
253};
254
255alignas(32) const MallocDebugK asan_malloc_dispatch_k = {
256 WRAP(malloc), WRAP(free), WRAP(calloc),
257 WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};
258
259alignas(32) const MallocDebugL asan_malloc_dispatch_l = {
260 WRAP(calloc),
261 WRAP(free),
262 WRAP(mallinfo),
263 WRAP(malloc),
264 WRAP(malloc_usable_size),
265 WRAP(memalign),
266 WRAP(posix_memalign),
267 WRAP(pvalloc),
268 WRAP(realloc),
269 WRAP(valloc)};
270
271namespace __asan {
272void ReplaceSystemMalloc() {
273 void** __libc_malloc_dispatch_p =
274 (void**)AsanDlSymNext("__libc_malloc_dispatch");
275 if (__libc_malloc_dispatch_p) {
276 // Decide on K vs L dispatch format by the presence of
277 // __libc_malloc_default_dispatch export in libc.
278 void* default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch");
279 if (default_dispatch_p)
280 *__libc_malloc_dispatch_p = (void*)&asan_malloc_dispatch_k;
281 else
282 *__libc_malloc_dispatch_p = (void*)&asan_malloc_dispatch_l;
283 }
284}
285} // namespace __asan
286
287# else // SANITIZER_ANDROID
288
289namespace __asan {
290void ReplaceSystemMalloc() {}
291} // namespace __asan
292# endif // SANITIZER_ANDROID
293
294#endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX ||
295 // SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_HAIKU
296