221 lines · cpp
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-exception6//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 || SANITIZER_HAIKU19 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 ---------------- {{{130using 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_LEAKS36 // Suppress leaks from dlerror(). Previously dlsym hack on global array was37 // used by leak sanitizer as a root region.38 __lsan_register_root_region(ptr, size);39# endif40 }41 static void OnFree(const void *ptr, uptr size) {42# if CAN_SANITIZE_LEAKS43 __lsan_unregister_root_region(ptr, size);44# endif45 }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);53}54 55#if SANITIZER_INTERCEPT_CFREE56INTERCEPTOR(void, cfree, void *ptr) {57 if (DlsymAlloc::PointerIsMine(ptr))58 return DlsymAlloc::Free(ptr);59 GET_STACK_TRACE_FREE;60 asan_free(ptr, &stack);61}62#endif // SANITIZER_INTERCEPT_CFREE63 64INTERCEPTOR(void*, malloc, uptr size) {65 if (DlsymAlloc::Use())66 return DlsymAlloc::Allocate(size);67 GET_STACK_TRACE_MALLOC;68 return asan_malloc(size, &stack);69}70 71INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {72 if (DlsymAlloc::Use())73 return DlsymAlloc::Callocate(nmemb, size);74 GET_STACK_TRACE_MALLOC;75 return asan_calloc(nmemb, size, &stack);76}77 78INTERCEPTOR(void*, realloc, void *ptr, uptr size) {79 if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))80 return DlsymAlloc::Realloc(ptr, size);81 GET_STACK_TRACE_MALLOC;82 return asan_realloc(ptr, size, &stack);83}84 85#if SANITIZER_INTERCEPT_REALLOCARRAY86INTERCEPTOR(void*, reallocarray, void *ptr, uptr nmemb, uptr size) {87 AsanInitFromRtl();88 GET_STACK_TRACE_MALLOC;89 return asan_reallocarray(ptr, nmemb, size, &stack);90}91#endif // SANITIZER_INTERCEPT_REALLOCARRAY92 93#if SANITIZER_INTERCEPT_MEMALIGN94INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {95 GET_STACK_TRACE_MALLOC;96 return asan_memalign(boundary, size, &stack);97}98 99INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {100 GET_STACK_TRACE_MALLOC;101 return asan_memalign(boundary, size, &stack);102}103#endif // SANITIZER_INTERCEPT_MEMALIGN104 105#if SANITIZER_INTERCEPT_ALIGNED_ALLOC106INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {107 GET_STACK_TRACE_MALLOC;108 return asan_aligned_alloc(boundary, size, &stack);109}110#endif // SANITIZER_INTERCEPT_ALIGNED_ALLOC111 112INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {113 GET_CURRENT_PC_BP_SP;114 (void)sp;115 return asan_malloc_usable_size(ptr, pc, bp);116}117 118#if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO119// We avoid including malloc.h for portability reasons.120// man mallinfo says the fields are "long", but the implementation uses int.121// It doesn't matter much -- we just need to make sure that the libc's mallinfo122// is not called.123struct fake_mallinfo {124 int x[10];125};126 127INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {128 struct fake_mallinfo res;129 REAL(memset)(&res, 0, sizeof(res));130 return res;131}132 133INTERCEPTOR(int, mallopt, int cmd, int value) {134 return 0;135}136#endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO137 138INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {139 GET_STACK_TRACE_MALLOC;140 return asan_posix_memalign(memptr, alignment, size, &stack);141}142 143INTERCEPTOR(void*, valloc, uptr size) {144 GET_STACK_TRACE_MALLOC;145 return asan_valloc(size, &stack);146}147 148#if SANITIZER_INTERCEPT_PVALLOC149INTERCEPTOR(void*, pvalloc, uptr size) {150 GET_STACK_TRACE_MALLOC;151 return asan_pvalloc(size, &stack);152}153#endif // SANITIZER_INTERCEPT_PVALLOC154 155INTERCEPTOR(void, malloc_stats, void) {156 __asan_print_accumulated_stats();157}158 159#if SANITIZER_ANDROID160// Format of __libc_malloc_dispatch has changed in Android L.161// While we are moving towards a solution that does not depend on bionic162// internals, here is something to support both K* and L releases.163struct MallocDebugK {164 void *(*malloc)(uptr bytes);165 void (*free)(void *mem);166 void *(*calloc)(uptr n_elements, uptr elem_size);167 void *(*realloc)(void *oldMem, uptr bytes);168 void *(*memalign)(uptr alignment, uptr bytes);169 uptr (*malloc_usable_size)(void *mem);170};171 172struct MallocDebugL {173 void *(*calloc)(uptr n_elements, uptr elem_size);174 void (*free)(void *mem);175 fake_mallinfo (*mallinfo)(void);176 void *(*malloc)(uptr bytes);177 uptr (*malloc_usable_size)(void *mem);178 void *(*memalign)(uptr alignment, uptr bytes);179 int (*posix_memalign)(void **memptr, uptr alignment, uptr size);180 void* (*pvalloc)(uptr size);181 void *(*realloc)(void *oldMem, uptr bytes);182 void* (*valloc)(uptr size);183};184 185alignas(32) const MallocDebugK asan_malloc_dispatch_k = {186 WRAP(malloc), WRAP(free), WRAP(calloc),187 WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};188 189alignas(32) const MallocDebugL asan_malloc_dispatch_l = {190 WRAP(calloc), WRAP(free), WRAP(mallinfo),191 WRAP(malloc), WRAP(malloc_usable_size), WRAP(memalign),192 WRAP(posix_memalign), WRAP(pvalloc), WRAP(realloc),193 WRAP(valloc)};194 195namespace __asan {196void ReplaceSystemMalloc() {197 void **__libc_malloc_dispatch_p =198 (void **)AsanDlSymNext("__libc_malloc_dispatch");199 if (__libc_malloc_dispatch_p) {200 // Decide on K vs L dispatch format by the presence of201 // __libc_malloc_default_dispatch export in libc.202 void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch");203 if (default_dispatch_p)204 *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k;205 else206 *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l;207 }208}209} // namespace __asan210 211#else // SANITIZER_ANDROID212 213namespace __asan {214void ReplaceSystemMalloc() {215}216} // namespace __asan217#endif // SANITIZER_ANDROID218 219#endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX ||220 // SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_HAIKU221