xref: /llvm-project/compiler-rt/lib/tysan/tysan_interceptors.cpp (revision e8c8543a1c728278bf323d34e451bcf9042d9257)
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