1 //===- nsan_interceptors.cpp ----------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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
16 //===----------------------------------------------------------------------===//
18 #include "interception/interception.h"
20 #include "nsan_thread.h"
21 #include "sanitizer_common/sanitizer_common.h"
22 #include "sanitizer_common/sanitizer_linux.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
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
);
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
);
48 INTERCEPTOR(void *, memmove
, void *dst
, const void *src
, uptr size
) {
49 // NOTE: This guard is needed because nsan's initialization code might call
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
),
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
);
66 INTERCEPTOR(void *, memcpy
, void *dst
, const void *src
, uptr size
) {
67 // NOTE: This guard is needed because nsan's initialization code might call
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
),
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
);
87 INTERCEPTOR(char *, strfry
, char *s
) {
88 const auto Len
= internal_strlen(s
);
89 char *res
= REAL(strfry
)(s
);
91 __nsan_set_value_unknown(reinterpret_cast<u8
*>(s
), Len
);
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);
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.
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
);
126 nsanCopyZeroTerminated(res
, S
, internal_strlen(S
));
131 INTERCEPTOR(wchar_t *, wcsdup
, const wchar_t *S
) {
132 wchar_t *res
= REAL(wcsdup
)(S
);
134 nsanWCopyZeroTerminated(res
, S
, wcslen(S
));
139 INTERCEPTOR(char *, strndup
, const char *S
, uptr size
) {
140 char *res
= REAL(strndup
)(S
, size
);
142 nsanCopyZeroTerminated(res
, S
, min(internal_strlen(S
), size
));
147 INTERCEPTOR(char *, strcpy
, char *dst
, const char *src
) {
148 char *res
= REAL(strcpy
)(dst
, src
);
149 nsanCopyZeroTerminated(dst
, src
, internal_strlen(src
));
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
));
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
)));
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
));
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
));
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
)));
186 INTERCEPTOR(char *, stpcpy
, char *dst
, const char *src
) {
187 char *res
= REAL(stpcpy
)(dst
, src
);
188 nsanCopyZeroTerminated(dst
, src
, internal_strlen(src
));
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
));
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
);
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
);
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
;
220 pthread_attr_init(&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
);
231 pthread_attr_destroy(&myattr
);
235 void __nsan::InitializeInterceptors() {
236 static bool initialized
= false;
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
);