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_GLIBC
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 *, mmap, void *addr, SIZE_T length, int prot, int flags,
57 int fd, OFF_T offset) {
58 void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
59 if (res != (void *)-1)
60 __tysan_set_type_unknown(addr: res, size: RoundUpTo(size: length, boundary: GetPageSize()));
61 return res;
62}
63
64#if !SANITIZER_APPLE
65INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags,
66 int fd, OFF64_T offset) {
67 void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
68 if (res != (void *)-1)
69 __tysan_set_type_unknown(addr: res, size: RoundUpTo(size: length, boundary: GetPageSize()));
70 return res;
71}
72#endif
73
74INTERCEPTOR(char *, strdup, const char *s) {
75 char *res = REAL(strdup)(s);
76 if (res)
77 tysan_copy_types(daddr: res, saddr: const_cast<char *>(s), size: internal_strlen(s));
78 return res;
79}
80
81#if TYSAN_INTERCEPT___STRDUP
82INTERCEPTOR(char *, __strdup, const char *s) {
83 char *res = REAL(__strdup)(s);
84 if (res)
85 tysan_copy_types(daddr: res, saddr: const_cast<char *>(s), size: internal_strlen(s));
86 return res;
87}
88#endif // TYSAN_INTERCEPT___STRDUP
89
90INTERCEPTOR(void *, malloc, uptr size) {
91 if (DlsymAlloc::Use())
92 return DlsymAlloc::Allocate(size_in_bytes: size);
93 void *res = REAL(malloc)(size);
94 if (res)
95 __tysan_set_type_unknown(addr: res, size);
96 return res;
97}
98
99#if SANITIZER_APPLE
100INTERCEPTOR(uptr, malloc_size, void *ptr) {
101 if (DlsymAlloc::PointerIsMine(ptr))
102 return DlsymAlloc::GetSize(ptr);
103 return REAL(malloc_size)(ptr);
104}
105#endif
106
107INTERCEPTOR(void *, realloc, void *ptr, uptr size) {
108 if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
109 return DlsymAlloc::Realloc(ptr, new_size: size);
110 void *res = REAL(realloc)(ptr, size);
111 // We might want to copy the types from the original allocation (although
112 // that would require that we knew its size).
113 if (res)
114 __tysan_set_type_unknown(addr: res, size);
115 return res;
116}
117
118INTERCEPTOR(void *, calloc, uptr nmemb, uptr size) {
119 if (DlsymAlloc::Use())
120 return DlsymAlloc::Callocate(nmemb, size);
121 void *res = REAL(calloc)(nmemb, size);
122 if (res)
123 __tysan_set_type_unknown(addr: res, size: nmemb * size);
124 return res;
125}
126
127INTERCEPTOR(void, free, void *ptr) {
128 if (DlsymAlloc::PointerIsMine(ptr))
129 return DlsymAlloc::Free(ptr);
130 REAL(free)(ptr);
131}
132
133INTERCEPTOR(void *, valloc, uptr size) {
134 void *res = REAL(valloc)(size);
135 if (res)
136 __tysan_set_type_unknown(addr: res, size);
137 return res;
138}
139
140#if SANITIZER_INTERCEPT_MEMALIGN
141INTERCEPTOR(void *, memalign, uptr alignment, uptr size) {
142 void *res = REAL(memalign)(alignment, size);
143 if (res)
144 __tysan_set_type_unknown(res, size);
145 return res;
146}
147#define TYSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
148#else
149#define TYSAN_MAYBE_INTERCEPT_MEMALIGN
150#endif // SANITIZER_INTERCEPT_MEMALIGN
151
152#if SANITIZER_INTERCEPT___LIBC_MEMALIGN
153INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
154 void *res = REAL(__libc_memalign)(alignment, size);
155 if (res)
156 __tysan_set_type_unknown(res, size);
157 return res;
158}
159#define TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN \
160 INTERCEPT_FUNCTION(__libc_memalign)
161#else
162#define TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN
163#endif // SANITIZER_INTERCEPT___LIBC_MEMALIGN
164
165#if SANITIZER_INTERCEPT_PVALLOC
166INTERCEPTOR(void *, pvalloc, uptr size) {
167 void *res = REAL(pvalloc)(size);
168 if (res)
169 __tysan_set_type_unknown(res, size);
170 return res;
171}
172#define TYSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
173#else
174#define TYSAN_MAYBE_INTERCEPT_PVALLOC
175#endif // SANITIZER_INTERCEPT_PVALLOC
176
177#if SANITIZER_INTERCEPT_ALIGNED_ALLOC
178INTERCEPTOR(void *, aligned_alloc, uptr alignment, uptr size) {
179 void *res = REAL(aligned_alloc)(alignment, size);
180 if (res)
181 __tysan_set_type_unknown(res, size);
182 return res;
183}
184#define TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc)
185#else
186#define TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC
187#endif
188
189INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
190 int res = REAL(posix_memalign)(memptr, alignment, size);
191 if (res == 0 && *memptr)
192 __tysan_set_type_unknown(addr: *memptr, size);
193 return res;
194}
195
196namespace __tysan {
197void InitializeInterceptors() {
198 static int inited = 0;
199 CHECK_EQ(inited, 0);
200
201 // Instruct libc malloc to consume less memory.
202#if SANITIZER_GLIBC
203 mallopt(param: 1, value: 0); // M_MXFAST
204 mallopt(param: -3, value: 32 * 1024); // M_MMAP_THRESHOLD
205#endif
206
207 INTERCEPT_FUNCTION(mmap);
208
209 INTERCEPT_FUNCTION(mmap64);
210
211 INTERCEPT_FUNCTION(strdup);
212#if TYSAN_INTERCEPT___STRDUP
213 INTERCEPT_FUNCTION(__strdup);
214#endif
215
216 INTERCEPT_FUNCTION(malloc);
217 INTERCEPT_FUNCTION(calloc);
218 INTERCEPT_FUNCTION(free);
219 INTERCEPT_FUNCTION(realloc);
220 INTERCEPT_FUNCTION(valloc);
221 TYSAN_MAYBE_INTERCEPT_MEMALIGN;
222 TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;
223 TYSAN_MAYBE_INTERCEPT_PVALLOC;
224 TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC
225 INTERCEPT_FUNCTION(posix_memalign);
226
227 INTERCEPT_FUNCTION(memset);
228 INTERCEPT_FUNCTION(memmove);
229
230 inited = 1;
231}
232} // namespace __tysan
233