1 //===-- tysan_interceptors.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 TypeSanitizer. 10 // 11 // Interceptors for standard library functions. 12 //===----------------------------------------------------------------------===// 13 14 #include "interception/interception.h" 15 #include "sanitizer_common/sanitizer_allocator_dlsym.h" 16 #include "sanitizer_common/sanitizer_common.h" 17 #include "tysan/tysan.h" 18 19 #if SANITIZER_LINUX && !SANITIZER_ANDROID 20 #define TYSAN_INTERCEPT___STRDUP 1 21 #else 22 #define TYSAN_INTERCEPT___STRDUP 0 23 #endif 24 25 #if SANITIZER_LINUX 26 extern "C" int mallopt(int param, int value); 27 #endif 28 29 using namespace __sanitizer; 30 using namespace __tysan; 31 32 namespace { 33 struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> { 34 static bool UseImpl() { return !tysan_inited; } 35 }; 36 } // namespace 37 38 INTERCEPTOR(void *, memset, void *dst, int v, uptr size) { 39 if (!tysan_inited && REAL(memset) == nullptr) 40 return internal_memset(dst, v, size); 41 42 void *res = REAL(memset)(dst, v, size); 43 tysan_set_type_unknown(dst, size); 44 return res; 45 } 46 47 INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) { 48 if (!tysan_inited && REAL(memmove) == nullptr) 49 return internal_memmove(dst, src, size); 50 51 void *res = REAL(memmove)(dst, src, size); 52 tysan_copy_types(dst, src, size); 53 return res; 54 } 55 56 INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) { 57 if (!tysan_inited && REAL(memcpy) == nullptr) { 58 // memmove is used here because on some platforms this will also 59 // intercept the memmove implementation. 60 return internal_memmove(dst, src, size); 61 } 62 63 void *res = REAL(memcpy)(dst, src, size); 64 tysan_copy_types(dst, src, size); 65 return res; 66 } 67 68 INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, 69 int fd, OFF_T offset) { 70 void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); 71 if (res != (void *)-1) 72 tysan_set_type_unknown(res, RoundUpTo(length, GetPageSize())); 73 return res; 74 } 75 76 #if !SANITIZER_APPLE 77 INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, 78 int fd, OFF64_T offset) { 79 void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); 80 if (res != (void *)-1) 81 tysan_set_type_unknown(res, RoundUpTo(length, GetPageSize())); 82 return res; 83 } 84 #endif 85 86 INTERCEPTOR(char *, strdup, const char *s) { 87 char *res = REAL(strdup)(s); 88 if (res) 89 tysan_copy_types(res, const_cast<char *>(s), internal_strlen(s)); 90 return res; 91 } 92 93 #if TYSAN_INTERCEPT___STRDUP 94 INTERCEPTOR(char *, __strdup, const char *s) { 95 char *res = REAL(__strdup)(s); 96 if (res) 97 tysan_copy_types(res, const_cast<char *>(s), internal_strlen(s)); 98 return res; 99 } 100 #endif // TYSAN_INTERCEPT___STRDUP 101 102 INTERCEPTOR(void *, malloc, uptr size) { 103 if (DlsymAlloc::Use()) 104 return DlsymAlloc::Allocate(size); 105 void *res = REAL(malloc)(size); 106 if (res) 107 tysan_set_type_unknown(res, size); 108 return res; 109 } 110 111 #if SANITIZER_APPLE 112 INTERCEPTOR(uptr, malloc_size, void *ptr) { 113 if (DlsymAlloc::PointerIsMine(ptr)) 114 return DlsymAlloc::GetSize(ptr); 115 return REAL(malloc_size)(ptr); 116 } 117 #endif 118 119 INTERCEPTOR(void *, realloc, void *ptr, uptr size) { 120 if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr)) 121 return DlsymAlloc::Realloc(ptr, size); 122 void *res = REAL(realloc)(ptr, size); 123 // We might want to copy the types from the original allocation (although 124 // that would require that we knew its size). 125 if (res) 126 tysan_set_type_unknown(res, size); 127 return res; 128 } 129 130 INTERCEPTOR(void *, calloc, uptr nmemb, uptr size) { 131 if (DlsymAlloc::Use()) 132 return DlsymAlloc::Callocate(nmemb, size); 133 void *res = REAL(calloc)(nmemb, size); 134 if (res) 135 tysan_set_type_unknown(res, nmemb * size); 136 return res; 137 } 138 139 INTERCEPTOR(void, free, void *ptr) { 140 if (DlsymAlloc::PointerIsMine(ptr)) 141 return DlsymAlloc::Free(ptr); 142 REAL(free)(ptr); 143 } 144 145 INTERCEPTOR(void *, valloc, uptr size) { 146 void *res = REAL(valloc)(size); 147 if (res) 148 tysan_set_type_unknown(res, size); 149 return res; 150 } 151 152 #if SANITIZER_INTERCEPT_MEMALIGN 153 INTERCEPTOR(void *, memalign, uptr alignment, uptr size) { 154 void *res = REAL(memalign)(alignment, size); 155 if (res) 156 tysan_set_type_unknown(res, size); 157 return res; 158 } 159 #define TYSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign) 160 #else 161 #define TYSAN_MAYBE_INTERCEPT_MEMALIGN 162 #endif // SANITIZER_INTERCEPT_MEMALIGN 163 164 #if SANITIZER_INTERCEPT___LIBC_MEMALIGN 165 INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) { 166 void *res = REAL(__libc_memalign)(alignment, size); 167 if (res) 168 tysan_set_type_unknown(res, size); 169 return res; 170 } 171 #define TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN \ 172 INTERCEPT_FUNCTION(__libc_memalign) 173 #else 174 #define TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN 175 #endif // SANITIZER_INTERCEPT___LIBC_MEMALIGN 176 177 #if SANITIZER_INTERCEPT_PVALLOC 178 INTERCEPTOR(void *, pvalloc, uptr size) { 179 void *res = REAL(pvalloc)(size); 180 if (res) 181 tysan_set_type_unknown(res, size); 182 return res; 183 } 184 #define TYSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc) 185 #else 186 #define TYSAN_MAYBE_INTERCEPT_PVALLOC 187 #endif // SANITIZER_INTERCEPT_PVALLOC 188 189 #if SANITIZER_INTERCEPT_ALIGNED_ALLOC 190 INTERCEPTOR(void *, aligned_alloc, uptr alignment, uptr size) { 191 void *res = REAL(aligned_alloc)(alignment, size); 192 if (res) 193 tysan_set_type_unknown(res, size); 194 return res; 195 } 196 #define TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc) 197 #else 198 #define TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC 199 #endif 200 201 INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { 202 int res = REAL(posix_memalign)(memptr, alignment, size); 203 if (res == 0 && *memptr) 204 tysan_set_type_unknown(*memptr, size); 205 return res; 206 } 207 208 namespace __tysan { 209 void InitializeInterceptors() { 210 static int inited = 0; 211 CHECK_EQ(inited, 0); 212 213 // Instruct libc malloc to consume less memory. 214 #if SANITIZER_LINUX 215 mallopt(1, 0); // M_MXFAST 216 mallopt(-3, 32 * 1024); // M_MMAP_THRESHOLD 217 #endif 218 219 INTERCEPT_FUNCTION(mmap); 220 221 INTERCEPT_FUNCTION(mmap64); 222 223 INTERCEPT_FUNCTION(strdup); 224 #if TYSAN_INTERCEPT___STRDUP 225 INTERCEPT_FUNCTION(__strdup); 226 #endif 227 228 INTERCEPT_FUNCTION(malloc); 229 INTERCEPT_FUNCTION(calloc); 230 INTERCEPT_FUNCTION(free); 231 INTERCEPT_FUNCTION(realloc); 232 INTERCEPT_FUNCTION(valloc); 233 TYSAN_MAYBE_INTERCEPT_MEMALIGN; 234 TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN; 235 TYSAN_MAYBE_INTERCEPT_PVALLOC; 236 TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC 237 INTERCEPT_FUNCTION(posix_memalign); 238 239 INTERCEPT_FUNCTION(memset); 240 INTERCEPT_FUNCTION(memmove); 241 INTERCEPT_FUNCTION(memcpy); 242 243 inited = 1; 244 } 245 } // namespace __tysan 246