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 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 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# include "sanitizer_common/sanitizer_tls_get_addr.h" 29 30// ---------------------- Replacement functions ---------------- {{{1 31using namespace __asan; 32 33struct 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); 40# endif 41 } 42 static void OnFree(const void *ptr, uptr size) { 43# if CAN_SANITIZE_LEAKS 44 __lsan_unregister_root_region(ptr, size); 45# endif 46 } 47}; 48 49INTERCEPTOR(void, free, void *ptr) { 50 if (DlsymAlloc::PointerIsMine(ptr)) 51 return DlsymAlloc::Free(ptr); 52 GET_STACK_TRACE_FREE; 53 asan_free(ptr, &stack, FROM_MALLOC); 54} 55 56#if SANITIZER_INTERCEPT_CFREE 57INTERCEPTOR(void, cfree, void *ptr) { 58 if (DlsymAlloc::PointerIsMine(ptr)) 59 return DlsymAlloc::Free(ptr); 60 GET_STACK_TRACE_FREE; 61 asan_free(ptr, &stack, FROM_MALLOC); 62} 63#endif // SANITIZER_INTERCEPT_CFREE 64 65INTERCEPTOR(void*, malloc, uptr size) { 66 if (DlsymAlloc::Use()) 67 return DlsymAlloc::Allocate(size); 68 ENSURE_ASAN_INITED(); 69 GET_STACK_TRACE_MALLOC; 70 return asan_malloc(size, &stack); 71} 72 73INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { 74 if (DlsymAlloc::Use()) 75 return DlsymAlloc::Callocate(nmemb, size); 76 ENSURE_ASAN_INITED(); 77 GET_STACK_TRACE_MALLOC; 78 return asan_calloc(nmemb, size, &stack); 79} 80 81INTERCEPTOR(void*, realloc, void *ptr, uptr size) { 82 if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr)) 83 return DlsymAlloc::Realloc(ptr, size); 84 ENSURE_ASAN_INITED(); 85 GET_STACK_TRACE_MALLOC; 86 return asan_realloc(ptr, size, &stack); 87} 88 89#if SANITIZER_INTERCEPT_REALLOCARRAY 90INTERCEPTOR(void*, reallocarray, void *ptr, uptr nmemb, uptr size) { 91 ENSURE_ASAN_INITED(); 92 GET_STACK_TRACE_MALLOC; 93 return asan_reallocarray(ptr, nmemb, size, &stack); 94} 95#endif // SANITIZER_INTERCEPT_REALLOCARRAY 96 97#if SANITIZER_INTERCEPT_MEMALIGN 98INTERCEPTOR(void*, memalign, uptr boundary, uptr size) { 99 GET_STACK_TRACE_MALLOC; 100 return asan_memalign(boundary, size, &stack, FROM_MALLOC); 101} 102 103INTERCEPTOR(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); 107 return res; 108} 109#endif // SANITIZER_INTERCEPT_MEMALIGN 110 111#if SANITIZER_INTERCEPT_ALIGNED_ALLOC 112INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) { 113 GET_STACK_TRACE_MALLOC; 114 return asan_aligned_alloc(boundary, size, &stack); 115} 116#endif // SANITIZER_INTERCEPT_ALIGNED_ALLOC 117 118INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { 119 GET_CURRENT_PC_BP_SP; 120 (void)sp; 121 return asan_malloc_usable_size(ptr, pc, bp); 122} 123 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 128// is not called. 129struct fake_mallinfo { 130 int x[10]; 131}; 132 133INTERCEPTOR(struct fake_mallinfo, mallinfo, void) { 134 struct fake_mallinfo res; 135 REAL(memset)(&res, 0, sizeof(res)); 136 return res; 137} 138 139INTERCEPTOR(int, mallopt, int cmd, int value) { 140 return 0; 141} 142#endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO 143 144INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { 145 GET_STACK_TRACE_MALLOC; 146 return asan_posix_memalign(memptr, alignment, size, &stack); 147} 148 149INTERCEPTOR(void*, valloc, uptr size) { 150 GET_STACK_TRACE_MALLOC; 151 return asan_valloc(size, &stack); 152} 153 154#if SANITIZER_INTERCEPT_PVALLOC 155INTERCEPTOR(void*, pvalloc, uptr size) { 156 GET_STACK_TRACE_MALLOC; 157 return asan_pvalloc(size, &stack); 158} 159#endif // SANITIZER_INTERCEPT_PVALLOC 160 161INTERCEPTOR(void, malloc_stats, void) { 162 __asan_print_accumulated_stats(); 163} 164 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. 169struct 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); 176}; 177 178struct 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); 189}; 190 191ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = { 192 WRAP(malloc), WRAP(free), WRAP(calloc), 193 WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)}; 194 195ALIGNED(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), 199 WRAP(valloc)}; 200 201namespace __asan { 202void 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; 211 else 212 *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l; 213 } 214} 215} // namespace __asan 216 217#else // SANITIZER_ANDROID 218 219namespace __asan { 220void ReplaceSystemMalloc() { 221} 222} // namespace __asan 223#endif // SANITIZER_ANDROID 224 225#endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || 226 // SANITIZER_NETBSD || SANITIZER_SOLARIS 227