1 //===- nsan_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 // Interceptors for memory allocation functions on ELF OSes. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "interception/interception.h" 14 #include "nsan/nsan.h" 15 #include "sanitizer_common/sanitizer_allocator_dlsym.h" 16 #include "sanitizer_common/sanitizer_common.h" 17 #include "sanitizer_common/sanitizer_platform.h" 18 #include "sanitizer_common/sanitizer_platform_interceptors.h" 19 20 #if !SANITIZER_APPLE && !SANITIZER_WINDOWS 21 using namespace __sanitizer; 22 using __nsan::nsan_initialized; 23 24 namespace { 25 struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> { 26 static bool UseImpl() { return !nsan_initialized; } 27 }; 28 } // namespace 29 30 INTERCEPTOR(void *, aligned_alloc, uptr align, uptr size) { 31 void *res = REAL(aligned_alloc)(align, size); 32 if (res) 33 __nsan_set_value_unknown(static_cast<u8 *>(res), size); 34 return res; 35 } 36 37 INTERCEPTOR(void *, calloc, uptr nmemb, uptr size) { 38 if (DlsymAlloc::Use()) 39 return DlsymAlloc::Callocate(nmemb, size); 40 41 void *res = REAL(calloc)(nmemb, size); 42 if (res) 43 __nsan_set_value_unknown(static_cast<u8 *>(res), nmemb * size); 44 return res; 45 } 46 47 INTERCEPTOR(void, free, void *ptr) { 48 if (DlsymAlloc::PointerIsMine(ptr)) 49 return DlsymAlloc::Free(ptr); 50 REAL(free)(ptr); 51 } 52 53 INTERCEPTOR(void *, malloc, uptr size) { 54 if (DlsymAlloc::Use()) 55 return DlsymAlloc::Allocate(size); 56 void *res = REAL(malloc)(size); 57 if (res) 58 __nsan_set_value_unknown(static_cast<u8 *>(res), size); 59 return res; 60 } 61 62 INTERCEPTOR(void *, realloc, void *ptr, uptr size) { 63 if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr)) 64 return DlsymAlloc::Realloc(ptr, size); 65 void *res = REAL(realloc)(ptr, size); 66 // TODO: We might want to copy the types from the original allocation 67 // (although that would require that we know its size). 68 if (res) 69 __nsan_set_value_unknown(static_cast<u8 *>(res), size); 70 return res; 71 } 72 73 #if SANITIZER_INTERCEPT_REALLOCARRAY 74 INTERCEPTOR(void *, reallocarray, void *ptr, uptr nmemb, uptr size) { 75 void *res = REAL(reallocarray)(ptr, nmemb, size); 76 if (res) 77 __nsan_set_value_unknown(static_cast<u8 *>(res), nmemb * size); 78 return res; 79 } 80 #endif // SANITIZER_INTERCEPT_REALLOCARRAY 81 82 INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr size) { 83 int res = REAL(posix_memalign)(memptr, align, size); 84 if (res == 0 && *memptr) 85 __nsan_set_value_unknown(static_cast<u8 *>(*memptr), size); 86 return res; 87 } 88 89 // Deprecated allocation functions (memalign, etc). 90 #if SANITIZER_INTERCEPT_MEMALIGN 91 INTERCEPTOR(void *, memalign, uptr align, uptr size) { 92 void *const res = REAL(memalign)(align, size); 93 if (res) 94 __nsan_set_value_unknown(static_cast<u8 *>(res), size); 95 return res; 96 } 97 98 INTERCEPTOR(void *, __libc_memalign, uptr align, uptr size) { 99 void *const res = REAL(__libc_memalign)(align, size); 100 if (res) 101 __nsan_set_value_unknown(static_cast<u8 *>(res), size); 102 return res; 103 } 104 #endif 105 106 void __nsan::InitializeMallocInterceptors() { 107 INTERCEPT_FUNCTION(aligned_alloc); 108 INTERCEPT_FUNCTION(calloc); 109 INTERCEPT_FUNCTION(free); 110 INTERCEPT_FUNCTION(malloc); 111 INTERCEPT_FUNCTION(posix_memalign); 112 INTERCEPT_FUNCTION(realloc); 113 #if SANITIZER_INTERCEPT_REALLOCARRAY 114 INTERCEPT_FUNCTION(reallocarray); 115 #endif 116 117 #if SANITIZER_INTERCEPT_MEMALIGN 118 INTERCEPT_FUNCTION(memalign); 119 INTERCEPT_FUNCTION(__libc_memalign); 120 #endif 121 } 122 123 #endif 124