1238901Sandrew//===-- asan_malloc_linux.cc ----------------------------------------------===// 2229109Sed// 3229109Sed// The LLVM Compiler Infrastructure 4229109Sed// 5229109Sed// This file is distributed under the University of Illinois Open Source 6229109Sed// License. See LICENSE.TXT for details. 7229109Sed// 8229109Sed//===----------------------------------------------------------------------===// 9229109Sed// 10229109Sed// This file is a part of AddressSanitizer, an address sanity checker. 11229109Sed// 12229109Sed// Linux-specific malloc interception. 13229109Sed// We simply define functions like malloc, free, realloc, etc. 14229109Sed// They will replace the corresponding libc functions automagically. 15229109Sed//===----------------------------------------------------------------------===// 16229109Sed 17251034Sed#include "sanitizer_common/sanitizer_platform.h" 18276789Sdim#if SANITIZER_FREEBSD || SANITIZER_LINUX 19251034Sed 20276789Sdim#include "sanitizer_common/sanitizer_tls_get_addr.h" 21229109Sed#include "asan_allocator.h" 22229109Sed#include "asan_interceptors.h" 23229109Sed#include "asan_internal.h" 24229109Sed#include "asan_stack.h" 25229109Sed 26229109Sed// ---------------------- Replacement functions ---------------- {{{1 27229109Sedusing namespace __asan; // NOLINT 28229109Sed 29296417Sdimstatic const uptr kCallocPoolSize = 1024; 30296417Sdimstatic uptr calloc_memory_for_dlsym[kCallocPoolSize]; 31296417Sdim 32296417Sdimstatic bool IsInCallocPool(const void *ptr) { 33296417Sdim sptr off = (sptr)ptr - (sptr)calloc_memory_for_dlsym; 34296417Sdim return 0 <= off && off < (sptr)kCallocPoolSize; 35296417Sdim} 36296417Sdim 37238901SandrewINTERCEPTOR(void, free, void *ptr) { 38245614Sandrew GET_STACK_TRACE_FREE; 39296417Sdim if (UNLIKELY(IsInCallocPool(ptr))) 40296417Sdim return; 41245614Sandrew asan_free(ptr, &stack, FROM_MALLOC); 42229109Sed} 43229109Sed 44238901SandrewINTERCEPTOR(void, cfree, void *ptr) { 45245614Sandrew GET_STACK_TRACE_FREE; 46296417Sdim if (UNLIKELY(IsInCallocPool(ptr))) 47296417Sdim return; 48245614Sandrew asan_free(ptr, &stack, FROM_MALLOC); 49229109Sed} 50229109Sed 51238901SandrewINTERCEPTOR(void*, malloc, uptr size) { 52245614Sandrew GET_STACK_TRACE_MALLOC; 53229109Sed return asan_malloc(size, &stack); 54229109Sed} 55229109Sed 56238901SandrewINTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { 57276789Sdim if (UNLIKELY(!asan_inited)) { 58238901Sandrew // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. 59238901Sandrew static uptr allocated; 60238901Sandrew uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize; 61229109Sed void *mem = (void*)&calloc_memory_for_dlsym[allocated]; 62229109Sed allocated += size_in_words; 63229109Sed CHECK(allocated < kCallocPoolSize); 64229109Sed return mem; 65229109Sed } 66245614Sandrew GET_STACK_TRACE_MALLOC; 67229109Sed return asan_calloc(nmemb, size, &stack); 68229109Sed} 69229109Sed 70238901SandrewINTERCEPTOR(void*, realloc, void *ptr, uptr size) { 71245614Sandrew GET_STACK_TRACE_MALLOC; 72296417Sdim if (UNLIKELY(IsInCallocPool(ptr))) { 73296417Sdim uptr offset = (uptr)ptr - (uptr)calloc_memory_for_dlsym; 74296417Sdim uptr copy_size = Min(size, kCallocPoolSize - offset); 75296417Sdim void *new_ptr = asan_malloc(size, &stack); 76296417Sdim internal_memcpy(new_ptr, ptr, copy_size); 77296417Sdim return new_ptr; 78296417Sdim } 79229109Sed return asan_realloc(ptr, size, &stack); 80229109Sed} 81229109Sed 82238901SandrewINTERCEPTOR(void*, memalign, uptr boundary, uptr size) { 83245614Sandrew GET_STACK_TRACE_MALLOC; 84245614Sandrew return asan_memalign(boundary, size, &stack, FROM_MALLOC); 85229109Sed} 86229109Sed 87276789SdimINTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) { 88276789Sdim GET_STACK_TRACE_MALLOC; 89276789Sdim return asan_memalign(boundary, size, &stack, FROM_MALLOC); 90276789Sdim} 91229109Sed 92276789SdimINTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) { 93276789Sdim GET_STACK_TRACE_MALLOC; 94276789Sdim void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC); 95276789Sdim DTLS_on_libc_memalign(res, size * boundary); 96276789Sdim return res; 97276789Sdim} 98276789Sdim 99238901SandrewINTERCEPTOR(uptr, malloc_usable_size, void *ptr) { 100274201Sdim GET_CURRENT_PC_BP_SP; 101274201Sdim (void)sp; 102274201Sdim return asan_malloc_usable_size(ptr, pc, bp); 103238901Sandrew} 104238901Sandrew 105238901Sandrew// We avoid including malloc.h for portability reasons. 106238901Sandrew// man mallinfo says the fields are "long", but the implementation uses int. 107238901Sandrew// It doesn't matter much -- we just need to make sure that the libc's mallinfo 108238901Sandrew// is not called. 109238901Sandrewstruct fake_mallinfo { 110238901Sandrew int x[10]; 111238901Sandrew}; 112238901Sandrew 113238901SandrewINTERCEPTOR(struct fake_mallinfo, mallinfo, void) { 114238901Sandrew struct fake_mallinfo res; 115238901Sandrew REAL(memset)(&res, 0, sizeof(res)); 116229109Sed return res; 117229109Sed} 118229109Sed 119238901SandrewINTERCEPTOR(int, mallopt, int cmd, int value) { 120229109Sed return -1; 121229109Sed} 122229109Sed 123238901SandrewINTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { 124245614Sandrew GET_STACK_TRACE_MALLOC; 125238901Sandrew // Printf("posix_memalign: %zx %zu\n", alignment, size); 126229109Sed return asan_posix_memalign(memptr, alignment, size, &stack); 127229109Sed} 128229109Sed 129238901SandrewINTERCEPTOR(void*, valloc, uptr size) { 130245614Sandrew GET_STACK_TRACE_MALLOC; 131229109Sed return asan_valloc(size, &stack); 132229109Sed} 133229109Sed 134238901SandrewINTERCEPTOR(void*, pvalloc, uptr size) { 135245614Sandrew GET_STACK_TRACE_MALLOC; 136229109Sed return asan_pvalloc(size, &stack); 137229109Sed} 138229109Sed 139245614SandrewINTERCEPTOR(void, malloc_stats, void) { 140245614Sandrew __asan_print_accumulated_stats(); 141245614Sandrew} 142245614Sandrew 143276789Sdim#if SANITIZER_ANDROID 144276789Sdim// Format of __libc_malloc_dispatch has changed in Android L. 145276789Sdim// While we are moving towards a solution that does not depend on bionic 146276789Sdim// internals, here is something to support both K* and L releases. 147276789Sdimstruct MallocDebugK { 148276789Sdim void *(*malloc)(uptr bytes); 149276789Sdim void (*free)(void *mem); 150276789Sdim void *(*calloc)(uptr n_elements, uptr elem_size); 151276789Sdim void *(*realloc)(void *oldMem, uptr bytes); 152276789Sdim void *(*memalign)(uptr alignment, uptr bytes); 153276789Sdim uptr (*malloc_usable_size)(void *mem); 154276789Sdim}; 155276789Sdim 156276789Sdimstruct MallocDebugL { 157276789Sdim void *(*calloc)(uptr n_elements, uptr elem_size); 158276789Sdim void (*free)(void *mem); 159276789Sdim fake_mallinfo (*mallinfo)(void); 160276789Sdim void *(*malloc)(uptr bytes); 161276789Sdim uptr (*malloc_usable_size)(void *mem); 162276789Sdim void *(*memalign)(uptr alignment, uptr bytes); 163276789Sdim int (*posix_memalign)(void **memptr, uptr alignment, uptr size); 164276789Sdim void* (*pvalloc)(uptr size); 165276789Sdim void *(*realloc)(void *oldMem, uptr bytes); 166276789Sdim void* (*valloc)(uptr size); 167276789Sdim}; 168276789Sdim 169276789SdimALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = { 170276789Sdim WRAP(malloc), WRAP(free), WRAP(calloc), 171276789Sdim WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)}; 172276789Sdim 173276789SdimALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = { 174276789Sdim WRAP(calloc), WRAP(free), WRAP(mallinfo), 175276789Sdim WRAP(malloc), WRAP(malloc_usable_size), WRAP(memalign), 176276789Sdim WRAP(posix_memalign), WRAP(pvalloc), WRAP(realloc), 177276789Sdim WRAP(valloc)}; 178276789Sdim 179276789Sdimnamespace __asan { 180276789Sdimvoid ReplaceSystemMalloc() { 181276789Sdim void **__libc_malloc_dispatch_p = 182276789Sdim (void **)AsanDlSymNext("__libc_malloc_dispatch"); 183276789Sdim if (__libc_malloc_dispatch_p) { 184276789Sdim // Decide on K vs L dispatch format by the presence of 185276789Sdim // __libc_malloc_default_dispatch export in libc. 186276789Sdim void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch"); 187276789Sdim if (default_dispatch_p) 188276789Sdim *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k; 189276789Sdim else 190276789Sdim *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l; 191276789Sdim } 192276789Sdim} 193276789Sdim} // namespace __asan 194276789Sdim 195276789Sdim#else // SANITIZER_ANDROID 196276789Sdim 197276789Sdimnamespace __asan { 198276789Sdimvoid ReplaceSystemMalloc() { 199276789Sdim} 200276789Sdim} // namespace __asan 201276789Sdim#endif // SANITIZER_ANDROID 202276789Sdim 203276789Sdim#endif // SANITIZER_FREEBSD || SANITIZER_LINUX 204