[AArch64] Fix SDNode type mismatches between *.td files and ISel (#116523)
[llvm-project.git] / compiler-rt / lib / nsan / nsan_interceptors.cpp
blob5f25eba85607057f1b3785e200dd6b312299fbac
1 //===- nsan_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 // Interceptors for standard library functions.
11 // A note about `printf`: Make sure none of the interceptor code calls any
12 // part of the nsan framework that can call `printf`, since this could create
13 // a loop (`printf` itself uses the libc). printf-free functions are documented
14 // as such in nsan.h.
16 //===----------------------------------------------------------------------===//
18 #include "interception/interception.h"
19 #include "nsan.h"
20 #include "nsan_thread.h"
21 #include "sanitizer_common/sanitizer_common.h"
22 #include "sanitizer_common/sanitizer_linux.h"
24 #include <wchar.h>
26 using namespace __nsan;
27 using namespace __sanitizer;
29 template <typename T> T min(T a, T b) { return a < b ? a : b; }
31 INTERCEPTOR(void *, memset, void *dst, int v, uptr size) {
32 // NOTE: This guard is needed because nsan's initialization code might call
33 // memset.
34 if (!nsan_initialized && REAL(memset) == nullptr)
35 return internal_memset(dst, v, size);
37 void *res = REAL(memset)(dst, v, size);
38 __nsan_set_value_unknown(static_cast<u8 *>(dst), size);
39 return res;
42 INTERCEPTOR(wchar_t *, wmemset, wchar_t *dst, wchar_t v, uptr size) {
43 wchar_t *res = REAL(wmemset)(dst, v, size);
44 __nsan_set_value_unknown((u8 *)dst, sizeof(wchar_t) * size);
45 return res;
48 INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) {
49 // NOTE: This guard is needed because nsan's initialization code might call
50 // memmove.
51 if (!nsan_initialized && REAL(memmove) == nullptr)
52 return internal_memmove(dst, src, size);
54 void *res = REAL(memmove)(dst, src, size);
55 __nsan_copy_values(static_cast<u8 *>(dst), static_cast<const u8 *>(src),
56 size);
57 return res;
60 INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dst, const wchar_t *src, uptr size) {
61 wchar_t *res = REAL(wmemmove)(dst, src, size);
62 __nsan_copy_values((u8 *)dst, (const u8 *)src, sizeof(wchar_t) * size);
63 return res;
66 INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) {
67 // NOTE: This guard is needed because nsan's initialization code might call
68 // memcpy.
69 if (!nsan_initialized && REAL(memcpy) == nullptr) {
70 // memmove is used here because on some platforms this will also
71 // intercept the memmove implementation.
72 return internal_memmove(dst, src, size);
75 void *res = REAL(memcpy)(dst, src, size);
76 __nsan_copy_values(static_cast<u8 *>(dst), static_cast<const u8 *>(src),
77 size);
78 return res;
81 INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dst, const wchar_t *src, uptr size) {
82 wchar_t *res = REAL(wmemcpy)(dst, src, size);
83 __nsan_copy_values((u8 *)dst, (const u8 *)src, sizeof(wchar_t) * size);
84 return res;
87 INTERCEPTOR(char *, strfry, char *s) {
88 const auto Len = internal_strlen(s);
89 char *res = REAL(strfry)(s);
90 if (res)
91 __nsan_set_value_unknown(reinterpret_cast<u8 *>(s), Len);
92 return res;
95 INTERCEPTOR(char *, strsep, char **Stringp, const char *delim) {
96 char *OrigStringp = REAL(strsep)(Stringp, delim);
97 if (*Stringp != nullptr) {
98 // The previous character has been overwritten with a '\0' char.
99 __nsan_set_value_unknown(reinterpret_cast<u8 *>(*Stringp) - 1, 1);
101 return OrigStringp;
104 INTERCEPTOR(char *, strtok, char *str, const char *delim) {
105 // This is overly conservative, but the probability that modern code is using
106 // strtok on double data is essentially zero anyway.
107 if (str)
108 __nsan_set_value_unknown(reinterpret_cast<u8 *>(str), internal_strlen(str));
109 return REAL(strtok)(str, delim);
112 static void nsanCopyZeroTerminated(char *dst, const char *src, uptr n) {
113 __nsan_copy_values(reinterpret_cast<u8 *>(dst),
114 reinterpret_cast<const u8 *>(src), n); // Data.
115 __nsan_set_value_unknown(reinterpret_cast<u8 *>(dst) + n, 1); // Terminator.
118 static void nsanWCopyZeroTerminated(wchar_t *dst, const wchar_t *src, uptr n) {
119 __nsan_copy_values((u8 *)dst, (const u8 *)(src), sizeof(wchar_t) * n);
120 __nsan_set_value_unknown((u8 *)(dst + n), sizeof(wchar_t));
123 INTERCEPTOR(char *, strdup, const char *S) {
124 char *res = REAL(strdup)(S);
125 if (res) {
126 nsanCopyZeroTerminated(res, S, internal_strlen(S));
128 return res;
131 INTERCEPTOR(wchar_t *, wcsdup, const wchar_t *S) {
132 wchar_t *res = REAL(wcsdup)(S);
133 if (res) {
134 nsanWCopyZeroTerminated(res, S, wcslen(S));
136 return res;
139 INTERCEPTOR(char *, strndup, const char *S, uptr size) {
140 char *res = REAL(strndup)(S, size);
141 if (res) {
142 nsanCopyZeroTerminated(res, S, min(internal_strlen(S), size));
144 return res;
147 INTERCEPTOR(char *, strcpy, char *dst, const char *src) {
148 char *res = REAL(strcpy)(dst, src);
149 nsanCopyZeroTerminated(dst, src, internal_strlen(src));
150 return res;
153 INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dst, const wchar_t *src) {
154 wchar_t *res = REAL(wcscpy)(dst, src);
155 nsanWCopyZeroTerminated(dst, src, wcslen(src));
156 return res;
159 INTERCEPTOR(char *, strncpy, char *dst, const char *src, uptr size) {
160 char *res = REAL(strncpy)(dst, src, size);
161 nsanCopyZeroTerminated(dst, src, min(size, internal_strlen(src)));
162 return res;
165 INTERCEPTOR(char *, strcat, char *dst, const char *src) {
166 const auto DstLenBeforeCat = internal_strlen(dst);
167 char *res = REAL(strcat)(dst, src);
168 nsanCopyZeroTerminated(dst + DstLenBeforeCat, src, internal_strlen(src));
169 return res;
172 INTERCEPTOR(wchar_t *, wcscat, wchar_t *dst, const wchar_t *src) {
173 const auto DstLenBeforeCat = wcslen(dst);
174 wchar_t *res = REAL(wcscat)(dst, src);
175 nsanWCopyZeroTerminated(dst + DstLenBeforeCat, src, wcslen(src));
176 return res;
179 INTERCEPTOR(char *, strncat, char *dst, const char *src, uptr size) {
180 const auto DstLen = internal_strlen(dst);
181 char *res = REAL(strncat)(dst, src, size);
182 nsanCopyZeroTerminated(dst + DstLen, src, min(size, internal_strlen(src)));
183 return res;
186 INTERCEPTOR(char *, stpcpy, char *dst, const char *src) {
187 char *res = REAL(stpcpy)(dst, src);
188 nsanCopyZeroTerminated(dst, src, internal_strlen(src));
189 return res;
192 INTERCEPTOR(wchar_t *, wcpcpy, wchar_t *dst, const wchar_t *src) {
193 wchar_t *res = REAL(wcpcpy)(dst, src);
194 nsanWCopyZeroTerminated(dst, src, wcslen(src));
195 return res;
198 INTERCEPTOR(uptr, strxfrm, char *dst, const char *src, uptr size) {
199 // This is overly conservative, but this function should very rarely be used.
200 __nsan_set_value_unknown(reinterpret_cast<u8 *>(dst), internal_strlen(dst));
201 const uptr res = REAL(strxfrm)(dst, src, size);
202 return res;
205 extern "C" int pthread_attr_init(void *attr);
206 extern "C" int pthread_attr_destroy(void *attr);
208 static void *NsanThreadStartFunc(void *arg) {
209 auto *t = reinterpret_cast<NsanThread *>(arg);
210 SetCurrentThread(t);
211 t->Init();
212 SetSigProcMask(&t->starting_sigset_, nullptr);
213 return t->ThreadStart();
216 INTERCEPTOR(int, pthread_create, void *th, void *attr,
217 void *(*callback)(void *), void *param) {
218 __sanitizer_pthread_attr_t myattr;
219 if (!attr) {
220 pthread_attr_init(&myattr);
221 attr = &myattr;
224 AdjustStackSize(attr);
226 NsanThread *t = NsanThread::Create(callback, param);
227 ScopedBlockSignals block(&t->starting_sigset_);
228 int res = REAL(pthread_create)(th, attr, NsanThreadStartFunc, t);
230 if (attr == &myattr)
231 pthread_attr_destroy(&myattr);
232 return res;
235 void __nsan::InitializeInterceptors() {
236 static bool initialized = false;
237 CHECK(!initialized);
239 InitializeMallocInterceptors();
241 INTERCEPT_FUNCTION(memset);
242 INTERCEPT_FUNCTION(wmemset);
243 INTERCEPT_FUNCTION(memmove);
244 INTERCEPT_FUNCTION(wmemmove);
245 INTERCEPT_FUNCTION(memcpy);
246 INTERCEPT_FUNCTION(wmemcpy);
248 INTERCEPT_FUNCTION(strdup);
249 INTERCEPT_FUNCTION(wcsdup);
250 INTERCEPT_FUNCTION(strndup);
251 INTERCEPT_FUNCTION(stpcpy);
252 INTERCEPT_FUNCTION(wcpcpy);
253 INTERCEPT_FUNCTION(strcpy);
254 INTERCEPT_FUNCTION(wcscpy);
255 INTERCEPT_FUNCTION(strncpy);
256 INTERCEPT_FUNCTION(strcat);
257 INTERCEPT_FUNCTION(wcscat);
258 INTERCEPT_FUNCTION(strncat);
259 INTERCEPT_FUNCTION(strxfrm);
261 INTERCEPT_FUNCTION(strfry);
262 INTERCEPT_FUNCTION(strsep);
263 INTERCEPT_FUNCTION(strtok);
265 INTERCEPT_FUNCTION(pthread_create);
267 initialized = 1;