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
26extern "C" int mallopt(int param, int value);
27#endif
28
29using namespace __sanitizer;
30using namespace __tysan;
31
32namespace {
33struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
34 static bool UseImpl() { return !tysan_inited; }
35};
36} // namespace
37
38INTERCEPTOR(void *, memset, void *dst, int v, uptr size) {
39 if (!tysan_inited && REAL(memset) == nullptr)
40 return internal_memset(s: dst, c: v, n: size);
41
42 void *res = REAL(memset)(dst, v, size);
43 tysan_set_type_unknown(addr: dst, size);
44 return res;
45}
46
47INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) {
48 if (!tysan_inited && REAL(memmove) == nullptr)
49 return internal_memmove(dest: dst, src, n: size);
50
51 void *res = REAL(memmove)(dst, src, size);
52 tysan_copy_types(daddr: dst, saddr: src, size);
53 return res;
54}
55
56INTERCEPTOR(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(dest: dst, src, n: size);
61 }
62
63 void *res = REAL(memcpy)(dst, src, size);
64 tysan_copy_types(daddr: dst, saddr: src, size);
65 return res;
66}
67
68INTERCEPTOR(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(addr: res, size: RoundUpTo(size: length, boundary: GetPageSize()));
73 return res;
74}
75
76#if !SANITIZER_APPLE
77INTERCEPTOR(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(addr: res, size: RoundUpTo(size: length, boundary: GetPageSize()));
82 return res;
83}
84#endif
85
86INTERCEPTOR(char *, strdup, const char *s) {
87 char *res = REAL(strdup)(s);
88 if (res)
89 tysan_copy_types(daddr: res, saddr: const_cast<char *>(s), size: internal_strlen(s));
90 return res;
91}
92
93#if TYSAN_INTERCEPT___STRDUP
94INTERCEPTOR(char *, __strdup, const char *s) {
95 char *res = REAL(__strdup)(s);
96 if (res)
97 tysan_copy_types(daddr: res, saddr: const_cast<char *>(s), size: internal_strlen(s));
98 return res;
99}
100#endif // TYSAN_INTERCEPT___STRDUP
101
102INTERCEPTOR(void *, malloc, uptr size) {
103 if (DlsymAlloc::Use())
104 return DlsymAlloc::Allocate(size_in_bytes: size);
105 void *res = REAL(malloc)(size);
106 if (res)
107 tysan_set_type_unknown(addr: res, size);
108 return res;
109}
110
111#if SANITIZER_APPLE
112INTERCEPTOR(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
119INTERCEPTOR(void *, realloc, void *ptr, uptr size) {
120 if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
121 return DlsymAlloc::Realloc(ptr, new_size: 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(addr: res, size);
127 return res;
128}
129
130INTERCEPTOR(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(addr: res, size: nmemb * size);
136 return res;
137}
138
139INTERCEPTOR(void, free, void *ptr) {
140 if (DlsymAlloc::PointerIsMine(ptr))
141 return DlsymAlloc::Free(ptr);
142 REAL(free)(ptr);
143}
144
145INTERCEPTOR(void *, valloc, uptr size) {
146 void *res = REAL(valloc)(size);
147 if (res)
148 tysan_set_type_unknown(addr: res, size);
149 return res;
150}
151
152#if SANITIZER_INTERCEPT_MEMALIGN
153INTERCEPTOR(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
165INTERCEPTOR(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
178INTERCEPTOR(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
190INTERCEPTOR(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
201INTERCEPTOR(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(addr: *memptr, size);
205 return res;
206}
207
208namespace __tysan {
209void 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(param: 1, value: 0); // M_MXFAST
216 mallopt(param: -3, value: 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