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_APPLE
26#define TYSAN_INTERCEPT_FUNC(name) \
27 do { \
28 if (!INTERCEPT_FUNCTION(name)) \
29 VReport(1, "TypeSanitizer: failed to intercept '%s'\n", #name); \
30 } while (0)
31#else // Apple interceptors don't need to be initialized with
32 // INTERCEPT_FUNCTION.
33#define TYSAN_INTERCEPT_FUNC(name)
34#endif
35
36#if SANITIZER_GLIBC
37extern "C" int mallopt(int param, int value);
38#endif
39
40using namespace __sanitizer;
41using namespace __tysan;
42
43namespace __tysan {
44// Defined in tysan.cpp
45void OnStackUnwind(const SignalContext &sig, const void *,
46 BufferedStackTrace *stack);
47
48static void TysanOnDeadlySignal(int signo, void *siginfo, void *context) {
49 HandleDeadlySignal(siginfo, context, tid: GetTid(), unwind: &OnStackUnwind, unwind_context: nullptr);
50}
51
52void InitializeDeadlySignals();
53} // namespace __tysan
54
55#define SIGNAL_INTERCEPTOR_ENTER() __tysan::InitializeDeadlySignals()
56#define COMMON_INTERCEPT_FUNCTION(name) TYSAN_INTERCEPT_FUNC(name)
57#include "sanitizer_common/sanitizer_signal_interceptors.inc"
58
59namespace __tysan {
60void InitializeDeadlySignals() {
61 static bool tysanSignalsInitialized = false;
62 if (tysanSignalsInitialized)
63 return;
64 InitializeSignalInterceptors();
65 InstallDeadlySignalHandlers(handler: &TysanOnDeadlySignal);
66 tysanSignalsInitialized = true;
67}
68} // namespace __tysan
69
70namespace {
71struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
72 static bool UseImpl() { return !tysan_inited; }
73};
74} // namespace
75
76INTERCEPTOR(void *, memset, void *dst, int v, uptr size) {
77 if (!tysan_inited && REAL(memset) == nullptr)
78 return internal_memset(s: dst, c: v, n: size);
79
80 void *res = REAL(memset)(dst, v, size);
81 __tysan_set_type_unknown(addr: dst, size);
82 return res;
83}
84
85INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) {
86 if (!tysan_inited && REAL(memmove) == nullptr)
87 return internal_memmove(dest: dst, src, n: size);
88
89 void *res = REAL(memmove)(dst, src, size);
90 tysan_copy_types(daddr: dst, saddr: src, size);
91 return res;
92}
93
94INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags,
95 int fd, OFF_T offset) {
96 void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
97 if (res != (void *)-1)
98 __tysan_set_type_unknown(addr: res, size: RoundUpTo(size: length, boundary: GetPageSize()));
99 return res;
100}
101
102#if !SANITIZER_APPLE
103INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags,
104 int fd, OFF64_T offset) {
105 void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
106 if (res != (void *)-1)
107 __tysan_set_type_unknown(addr: res, size: RoundUpTo(size: length, boundary: GetPageSize()));
108 return res;
109}
110#endif
111
112INTERCEPTOR(char *, strdup, const char *s) {
113 char *res = REAL(strdup)(s);
114 if (res)
115 tysan_copy_types(daddr: res, saddr: const_cast<char *>(s), size: internal_strlen(s));
116 return res;
117}
118
119#if TYSAN_INTERCEPT___STRDUP
120INTERCEPTOR(char *, __strdup, const char *s) {
121 char *res = REAL(__strdup)(s);
122 if (res)
123 tysan_copy_types(daddr: res, saddr: const_cast<char *>(s), size: internal_strlen(s));
124 return res;
125}
126#endif // TYSAN_INTERCEPT___STRDUP
127
128INTERCEPTOR(void *, malloc, uptr size) {
129 if (DlsymAlloc::Use())
130 return DlsymAlloc::Allocate(size_in_bytes: size);
131 void *res = REAL(malloc)(size);
132 if (res)
133 __tysan_set_type_unknown(addr: res, size);
134 return res;
135}
136
137#if SANITIZER_APPLE
138INTERCEPTOR(uptr, malloc_size, void *ptr) {
139 if (DlsymAlloc::PointerIsMine(ptr))
140 return DlsymAlloc::GetSize(ptr);
141 return REAL(malloc_size)(ptr);
142}
143#endif
144
145INTERCEPTOR(void *, realloc, void *ptr, uptr size) {
146 if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
147 return DlsymAlloc::Realloc(ptr, new_size: size);
148 void *res = REAL(realloc)(ptr, size);
149 // We might want to copy the types from the original allocation (although
150 // that would require that we knew its size).
151 if (res)
152 __tysan_set_type_unknown(addr: res, size);
153 return res;
154}
155
156INTERCEPTOR(void *, calloc, uptr nmemb, uptr size) {
157 if (DlsymAlloc::Use())
158 return DlsymAlloc::Callocate(nmemb, size);
159 void *res = REAL(calloc)(nmemb, size);
160 if (res)
161 __tysan_set_type_unknown(addr: res, size: nmemb * size);
162 return res;
163}
164
165INTERCEPTOR(void, free, void *ptr) {
166 if (DlsymAlloc::PointerIsMine(ptr))
167 return DlsymAlloc::Free(ptr);
168 REAL(free)(ptr);
169}
170
171INTERCEPTOR(void *, valloc, uptr size) {
172 void *res = REAL(valloc)(size);
173 if (res)
174 __tysan_set_type_unknown(addr: res, size);
175 return res;
176}
177
178#if SANITIZER_INTERCEPT_MEMALIGN
179INTERCEPTOR(void *, memalign, uptr alignment, uptr size) {
180 void *res = REAL(memalign)(alignment, size);
181 if (res)
182 __tysan_set_type_unknown(addr: res, size);
183 return res;
184}
185#define TYSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
186#else
187#define TYSAN_MAYBE_INTERCEPT_MEMALIGN
188#endif // SANITIZER_INTERCEPT_MEMALIGN
189
190#if SANITIZER_INTERCEPT___LIBC_MEMALIGN
191INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
192 void *res = REAL(__libc_memalign)(alignment, size);
193 if (res)
194 __tysan_set_type_unknown(addr: res, size);
195 return res;
196}
197#define TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN \
198 INTERCEPT_FUNCTION(__libc_memalign)
199#else
200#define TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN
201#endif // SANITIZER_INTERCEPT___LIBC_MEMALIGN
202
203#if SANITIZER_INTERCEPT_PVALLOC
204INTERCEPTOR(void *, pvalloc, uptr size) {
205 void *res = REAL(pvalloc)(size);
206 if (res)
207 __tysan_set_type_unknown(addr: res, size);
208 return res;
209}
210#define TYSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
211#else
212#define TYSAN_MAYBE_INTERCEPT_PVALLOC
213#endif // SANITIZER_INTERCEPT_PVALLOC
214
215#if SANITIZER_INTERCEPT_ALIGNED_ALLOC
216INTERCEPTOR(void *, aligned_alloc, uptr alignment, uptr size) {
217 void *res = REAL(aligned_alloc)(alignment, size);
218 if (res)
219 __tysan_set_type_unknown(addr: res, size);
220 return res;
221}
222#define TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc)
223#else
224#define TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC
225#endif
226
227INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
228 int res = REAL(posix_memalign)(memptr, alignment, size);
229 if (res == 0 && *memptr)
230 __tysan_set_type_unknown(addr: *memptr, size);
231 return res;
232}
233
234namespace __tysan {
235void InitializeInterceptors() {
236 static int inited = 0;
237 CHECK_EQ(inited, 0);
238
239 // Instruct libc malloc to consume less memory.
240#if SANITIZER_GLIBC
241 mallopt(param: 1, value: 0); // M_MXFAST
242 mallopt(param: -3, value: 32 * 1024); // M_MMAP_THRESHOLD
243#endif
244
245 INTERCEPT_FUNCTION(mmap);
246
247 INTERCEPT_FUNCTION(mmap64);
248
249 INTERCEPT_FUNCTION(strdup);
250#if TYSAN_INTERCEPT___STRDUP
251 INTERCEPT_FUNCTION(__strdup);
252#endif
253
254 INTERCEPT_FUNCTION(malloc);
255 INTERCEPT_FUNCTION(calloc);
256 INTERCEPT_FUNCTION(free);
257 INTERCEPT_FUNCTION(realloc);
258 INTERCEPT_FUNCTION(valloc);
259 TYSAN_MAYBE_INTERCEPT_MEMALIGN;
260 TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;
261 TYSAN_MAYBE_INTERCEPT_PVALLOC;
262 TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC;
263 INTERCEPT_FUNCTION(posix_memalign);
264
265 INTERCEPT_FUNCTION(memset);
266 INTERCEPT_FUNCTION(memmove);
267
268 inited = 1;
269}
270} // namespace __tysan
271