1//===-- asan_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 AddressSanitizer, an address sanity checker.
10//
11// Intercept various libc functions.
12//===----------------------------------------------------------------------===//
13
14#include "asan_interceptors.h"
15
16#include "asan_allocator.h"
17#include "asan_internal.h"
18#include "asan_mapping.h"
19#include "asan_poisoning.h"
20#include "asan_report.h"
21#include "asan_stack.h"
22#include "asan_stats.h"
23#include "asan_suppressions.h"
24#include "asan_thread.h"
25#include "lsan/lsan_common.h"
26#include "sanitizer_common/sanitizer_errno.h"
27#include "sanitizer_common/sanitizer_internal_defs.h"
28#include "sanitizer_common/sanitizer_libc.h"
29
30// There is no general interception at all on Fuchsia.
31// Only the functions in asan_interceptors_memintrinsics.cpp are
32// really defined to replace libc functions.
33#if !SANITIZER_FUCHSIA
34
35# if SANITIZER_POSIX
36# include "sanitizer_common/sanitizer_posix.h"
37# endif
38
39# if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION || \
40 ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION
41# include <unwind.h>
42# endif
43
44# if defined(__i386) && SANITIZER_LINUX
45# define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1"
46# elif defined(__mips__) && SANITIZER_LINUX
47# define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2"
48# endif
49
50namespace __asan {
51
52#define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \
53 ASAN_READ_RANGE((ctx), (s), \
54 common_flags()->strict_string_checks ? (len) + 1 : (n))
55
56# define ASAN_READ_STRING(ctx, s, n) \
57 ASAN_READ_STRING_OF_LEN((ctx), (s), internal_strlen(s), (n))
58
59static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
60#if SANITIZER_INTERCEPT_STRNLEN
61 if (REAL(strnlen)) {
62 return REAL(strnlen)(s, maxlen);
63 }
64#endif
65 return internal_strnlen(s, maxlen);
66}
67
68void SetThreadName(const char *name) {
69 AsanThread *t = GetCurrentThread();
70 if (t)
71 asanThreadRegistry().SetThreadName(tid: t->tid(), name);
72}
73
74int OnExit() {
75 if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks &&
76 __lsan::HasReportedLeaks()) {
77 return common_flags()->exitcode;
78 }
79 // FIXME: ask frontend whether we need to return failure.
80 return 0;
81}
82
83} // namespace __asan
84
85// ---------------------- Wrappers ---------------- {{{1
86using namespace __asan;
87
88DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, usize)
89DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
90
91#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \
92 ASAN_INTERCEPT_FUNC_VER(name, ver)
93#define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \
94 ASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver)
95#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
96 ASAN_WRITE_RANGE(ctx, ptr, size)
97#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
98 ASAN_READ_RANGE(ctx, ptr, size)
99# define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
100 ASAN_INTERCEPTOR_ENTER(ctx, func); \
101 do { \
102 if constexpr (SANITIZER_APPLE) { \
103 if (UNLIKELY(!AsanInited())) \
104 return REAL(func)(__VA_ARGS__); \
105 } else { \
106 if (!TryAsanInitFromRtl()) \
107 return REAL(func)(__VA_ARGS__); \
108 } \
109 } while (false)
110#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
111 do { \
112 } while (false)
113#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
114 do { \
115 } while (false)
116#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
117 do { \
118 } while (false)
119#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
120 do { \
121 } while (false)
122#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
123// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name)
124// But asan does not remember UserId's for threads (pthread_t);
125// and remembers all ever existed threads, so the linear search by UserId
126// can be slow.
127#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
128 do { \
129 } while (false)
130#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
131// Strict init-order checking is dlopen-hostile:
132// https://github.com/google/sanitizers/issues/178
133# define COMMON_INTERCEPTOR_DLOPEN(filename, flag) \
134 ({ \
135 if (flags()->strict_init_order) \
136 StopInitOrderChecking(); \
137 CheckNoDeepBind(filename, flag); \
138 REAL(dlopen)(filename, flag); \
139 })
140# define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
141# define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)
142# define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()
143# define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!AsanInited())
144# define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
145 if (AsanThread *t = GetCurrentThread()) { \
146 *begin = t->tls_begin(); \
147 *end = t->tls_end(); \
148 } else { \
149 *begin = *end = 0; \
150 }
151
152template <class Mmap>
153static void* mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,
154 int prot, int flags, int fd, OFF64_T offset) {
155 void *res = real_mmap(addr, length, prot, flags, fd, offset);
156 if (length && res != (void *)-1) {
157 const uptr beg = reinterpret_cast<uptr>(res);
158 DCHECK(IsAligned(beg, GetPageSize()));
159 SIZE_T rounded_length = RoundUpTo(size: length, boundary: GetPageSize());
160 // Only unpoison shadow if it's an ASAN managed address.
161 if (AddrIsInMem(a: beg) && AddrIsInMem(a: beg + rounded_length - 1))
162 PoisonShadow(addr: beg, size: RoundUpTo(size: length, boundary: GetPageSize()), value: 0);
163 }
164 return res;
165}
166
167template <class Munmap>
168static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) {
169 // We should not tag if munmap fail, but it's to late to tag after
170 // real_munmap, as the pages could be mmaped by another thread.
171 const uptr beg = reinterpret_cast<uptr>(addr);
172 if (length && IsAligned(a: beg, alignment: GetPageSize())) {
173 SIZE_T rounded_length = RoundUpTo(size: length, boundary: GetPageSize());
174 // Protect from unmapping the shadow.
175 if (AddrIsInMem(a: beg) && AddrIsInMem(a: beg + rounded_length - 1))
176 PoisonShadow(addr: beg, size: rounded_length, value: 0);
177 }
178 return real_munmap(addr, length);
179}
180
181# define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, \
182 fd, offset) \
183 do { \
184 (void)(ctx); \
185 return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off); \
186 } while (false)
187
188# define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length) \
189 do { \
190 (void)(ctx); \
191 return munmap_interceptor(REAL(munmap), addr, sz); \
192 } while (false)
193
194#if CAN_SANITIZE_LEAKS
195#define COMMON_INTERCEPTOR_STRERROR() \
196 __lsan::ScopedInterceptorDisabler disabler
197#endif
198
199# define SIGNAL_INTERCEPTOR_ENTER() \
200 do { \
201 AsanInitFromRtl(); \
202 } while (false)
203
204# include "sanitizer_common/sanitizer_common_interceptors.inc"
205# include "sanitizer_common/sanitizer_signal_interceptors.inc"
206
207// Syscall interceptors don't have contexts, we don't support suppressions
208// for them.
209#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s)
210#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s)
211#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
212 do { \
213 (void)(p); \
214 (void)(s); \
215 } while (false)
216#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
217 do { \
218 (void)(p); \
219 (void)(s); \
220 } while (false)
221#include "sanitizer_common/sanitizer_common_syscalls.inc"
222#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
223
224#if ASAN_INTERCEPT_PTHREAD_CREATE
225static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
226 AsanThread *t = (AsanThread *)arg;
227 SetCurrentThread(t);
228 auto self = GetThreadSelf();
229 auto args = asanThreadArgRetval().GetArgs(thread: self);
230 t->ThreadStart(os_id: GetTid());
231
232# if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
233 SANITIZER_SOLARIS
234 __sanitizer_sigset_t sigset;
235 t->GetStartData(data&: sigset);
236 SetSigProcMask(set: &sigset, oldset: nullptr);
237# endif
238
239 thread_return_t retval = (*args.routine)(args.arg_retval);
240 asanThreadArgRetval().Finish(thread: self, retval);
241 return retval;
242}
243
244INTERCEPTOR(int, pthread_create, void *thread, void *attr,
245 void *(*start_routine)(void *), void *arg) {
246 EnsureMainThreadIDIsCorrect();
247 // Strict init-order checking is thread-hostile.
248 if (flags()->strict_init_order)
249 StopInitOrderChecking();
250 GET_STACK_TRACE_THREAD;
251 bool detached = [attr]() {
252 int d = 0;
253 return attr && !REAL(pthread_attr_getdetachstate)(attr, &d) &&
254 IsStateDetached(state: d);
255 }();
256
257 u32 current_tid = GetCurrentTidOrInvalid();
258
259 __sanitizer_sigset_t sigset = {};
260# if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
261 SANITIZER_SOLARIS
262 ScopedBlockSignals block(&sigset);
263# endif
264
265 AsanThread *t = AsanThread::Create(data: sigset, parent_tid: current_tid, stack: &stack, detached);
266
267 int result;
268 {
269 // Ignore all allocations made by pthread_create: thread stack/TLS may be
270 // stored by pthread for future reuse even after thread destruction, and
271 // the linked list it's stored in doesn't even hold valid pointers to the
272 // objects, the latter are calculated by obscure pointer arithmetic.
273# if CAN_SANITIZE_LEAKS
274 __lsan::ScopedInterceptorDisabler disabler;
275# endif
276 asanThreadArgRetval().Create(detached, args: {.routine: start_routine, .arg_retval: arg}, fn: [&]() -> uptr {
277 result = REAL(pthread_create)(thread, attr, asan_thread_start, t);
278 return result ? 0 : *(uptr *)(thread);
279 });
280 }
281 if (result != 0) {
282 // If the thread didn't start delete the AsanThread to avoid leaking it.
283 // Note AsanThreadContexts never get destroyed so the AsanThreadContext
284 // that was just created for the AsanThread is wasted.
285 t->Destroy();
286 }
287 return result;
288}
289
290INTERCEPTOR(int, pthread_join, void *thread, void **retval) {
291 int result;
292 asanThreadArgRetval().Join(thread: (uptr)thread, fn: [&]() {
293 result = REAL(pthread_join)(thread, retval);
294 return !result;
295 });
296 return result;
297}
298
299INTERCEPTOR(int, pthread_detach, void *thread) {
300 int result;
301 asanThreadArgRetval().Detach(thread: (uptr)thread, fn: [&]() {
302 result = REAL(pthread_detach)(thread);
303 return !result;
304 });
305 return result;
306}
307
308INTERCEPTOR(void, pthread_exit, void *retval) {
309 asanThreadArgRetval().Finish(thread: GetThreadSelf(), retval);
310 REAL(pthread_exit)(retval);
311}
312
313# if ASAN_INTERCEPT_TRYJOIN
314INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) {
315 int result;
316 asanThreadArgRetval().Join(thread: (uptr)thread, fn: [&]() {
317 result = REAL(pthread_tryjoin_np)(thread, ret);
318 return !result;
319 });
320 return result;
321}
322# endif
323
324# if ASAN_INTERCEPT_TIMEDJOIN
325INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,
326 const struct timespec *abstime) {
327 int result;
328 asanThreadArgRetval().Join(thread: (uptr)thread, fn: [&]() {
329 result = REAL(pthread_timedjoin_np)(thread, ret, abstime);
330 return !result;
331 });
332 return result;
333}
334# endif
335
336DEFINE_INTERNAL_PTHREAD_FUNCTIONS
337#endif // ASAN_INTERCEPT_PTHREAD_CREATE
338
339#if ASAN_INTERCEPT_SWAPCONTEXT
340static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {
341 // Only clear if we know the stack. This should be true only for contexts
342 // created with makecontext().
343 if (!ssize)
344 return;
345 // Align to page size.
346 uptr PageSize = GetPageSizeCached();
347 uptr bottom = RoundDownTo(x: stack, boundary: PageSize);
348 if (!AddrIsInMem(a: bottom))
349 return;
350 ssize += stack - bottom;
351 ssize = RoundUpTo(size: ssize, boundary: PageSize);
352 PoisonShadow(addr: bottom, size: ssize, value: 0);
353}
354
355// Since Solaris 10/SPARC, ucp->uc_stack.ss_sp refers to the stack base address
356// as on other targets. For binary compatibility, the new version uses a
357// different external name, so we intercept that.
358# if SANITIZER_SOLARIS && defined(__sparc__)
359INTERCEPTOR(void, __makecontext_v2, struct ucontext_t *ucp, void (*func)(),
360 int argc, ...) {
361# else
362INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc,
363 ...) {
364# endif
365 va_list ap;
366 uptr args[64];
367 // We don't know a better way to forward ... into REAL function. We can
368 // increase args size if necessary.
369 CHECK_LE(argc, ARRAY_SIZE(args));
370 internal_memset(s: args, c: 0, n: sizeof(args));
371 va_start(ap, argc);
372 for (int i = 0; i < argc; ++i) args[i] = va_arg(ap, uptr);
373 va_end(ap);
374
375# define ENUMERATE_ARRAY_4(start) \
376 args[start], args[start + 1], args[start + 2], args[start + 3]
377# define ENUMERATE_ARRAY_16(start) \
378 ENUMERATE_ARRAY_4(start), ENUMERATE_ARRAY_4(start + 4), \
379 ENUMERATE_ARRAY_4(start + 8), ENUMERATE_ARRAY_4(start + 12)
380# define ENUMERATE_ARRAY_64() \
381 ENUMERATE_ARRAY_16(0), ENUMERATE_ARRAY_16(16), ENUMERATE_ARRAY_16(32), \
382 ENUMERATE_ARRAY_16(48)
383
384# if SANITIZER_SOLARIS && defined(__sparc__)
385 REAL(__makecontext_v2)
386# else
387 REAL(makecontext)
388# endif
389 ((struct ucontext_t *)ucp, func, argc, ENUMERATE_ARRAY_64());
390
391# undef ENUMERATE_ARRAY_4
392# undef ENUMERATE_ARRAY_16
393# undef ENUMERATE_ARRAY_64
394
395 // Sign the stack so we can identify it for unpoisoning.
396 SignContextStack(context: ucp);
397}
398
399INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
400 struct ucontext_t *ucp) {
401 static bool reported_warning = false;
402 if (!reported_warning) {
403 Report(format: "WARNING: ASan doesn't fully support makecontext/swapcontext "
404 "functions and may produce false positives in some cases!\n");
405 reported_warning = true;
406 }
407 // Clear shadow memory for new context (it may share stack
408 // with current context).
409 uptr stack, ssize;
410 ReadContextStack(context: ucp, stack: &stack, ssize: &ssize);
411 ClearShadowMemoryForContextStack(stack, ssize);
412
413# if __has_attribute(__indirect_return__) && \
414 (defined(__x86_64__) || defined(__i386__))
415 int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *)
416 __attribute__((__indirect_return__)) = REAL(swapcontext);
417 int res = real_swapcontext(oucp, ucp);
418# else
419 int res = REAL(swapcontext)(oucp, ucp);
420# endif
421 // swapcontext technically does not return, but program may swap context to
422 // "oucp" later, that would look as if swapcontext() returned 0.
423 // We need to clear shadow for ucp once again, as it may be in arbitrary
424 // state.
425 ClearShadowMemoryForContextStack(stack, ssize);
426 return res;
427}
428#endif // ASAN_INTERCEPT_SWAPCONTEXT
429
430#if SANITIZER_NETBSD
431#define longjmp __longjmp14
432#define siglongjmp __siglongjmp14
433#endif
434
435INTERCEPTOR(void, longjmp, void *env, int val) {
436 __asan_handle_no_return();
437 REAL(longjmp)(env, val);
438}
439
440#if ASAN_INTERCEPT__LONGJMP
441INTERCEPTOR(void, _longjmp, void *env, int val) {
442 __asan_handle_no_return();
443 REAL(_longjmp)(env, val);
444}
445#endif
446
447#if ASAN_INTERCEPT___LONGJMP_CHK
448INTERCEPTOR(void, __longjmp_chk, void *env, int val) {
449 __asan_handle_no_return();
450 REAL(__longjmp_chk)(env, val);
451}
452#endif
453
454#if ASAN_INTERCEPT_SIGLONGJMP
455INTERCEPTOR(void, siglongjmp, void *env, int val) {
456 __asan_handle_no_return();
457 REAL(siglongjmp)(env, val);
458}
459#endif
460
461#if ASAN_INTERCEPT___CXA_THROW
462INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
463 CHECK(REAL(__cxa_throw));
464 __asan_handle_no_return();
465 REAL(__cxa_throw)(a, b, c);
466}
467#endif
468
469#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION
470INTERCEPTOR(void, __cxa_rethrow_primary_exception, void *a) {
471 CHECK(REAL(__cxa_rethrow_primary_exception));
472 __asan_handle_no_return();
473 REAL(__cxa_rethrow_primary_exception)(a);
474}
475#endif
476
477#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION
478INTERCEPTOR(_Unwind_Reason_Code, _Unwind_RaiseException,
479 _Unwind_Exception *object) {
480 CHECK(REAL(_Unwind_RaiseException));
481 __asan_handle_no_return();
482 return REAL(_Unwind_RaiseException)(object);
483}
484#endif
485
486#if ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION
487INTERCEPTOR(_Unwind_Reason_Code, _Unwind_SjLj_RaiseException,
488 _Unwind_Exception *object) {
489 CHECK(REAL(_Unwind_SjLj_RaiseException));
490 __asan_handle_no_return();
491 return REAL(_Unwind_SjLj_RaiseException)(object);
492}
493#endif
494
495#if ASAN_INTERCEPT_INDEX
496# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
497INTERCEPTOR(char*, index, const char *string, int c)
498 ALIAS(WRAP(strchr));
499# else
500# if SANITIZER_APPLE
501DECLARE_REAL(char*, index, const char *string, int c)
502OVERRIDE_FUNCTION(index, strchr);
503# else
504DEFINE_REAL(char*, index, const char *string, int c)
505# endif
506# endif
507#endif // ASAN_INTERCEPT_INDEX
508
509// For both strcat() and strncat() we need to check the validity of |to|
510// argument irrespective of the |from| length.
511 INTERCEPTOR(char *, strcat, char *to, const char *from) {
512 void *ctx;
513 ASAN_INTERCEPTOR_ENTER(ctx, strcat);
514 AsanInitFromRtl();
515 if (flags()->replace_str) {
516 uptr from_length = internal_strlen(s: from);
517 ASAN_READ_RANGE(ctx, from, from_length + 1);
518 uptr to_length = internal_strlen(s: to);
519 ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
520 ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
521 // If the copying actually happens, the |from| string should not overlap
522 // with the resulting string starting at |to|, which has a length of
523 // to_length + from_length + 1.
524 if (from_length > 0) {
525 CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1, from,
526 from_length + 1);
527 }
528 }
529 return REAL(strcat)(to, from);
530 }
531
532INTERCEPTOR(char*, strncat, char *to, const char *from, usize size) {
533 void *ctx;
534 ASAN_INTERCEPTOR_ENTER(ctx, strncat);
535 AsanInitFromRtl();
536 if (flags()->replace_str) {
537 uptr from_length = MaybeRealStrnlen(s: from, maxlen: size);
538 uptr copy_length = Min<uptr>(a: size, b: from_length + 1);
539 ASAN_READ_RANGE(ctx, from, copy_length);
540 uptr to_length = internal_strlen(s: to);
541 ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
542 ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
543 if (from_length > 0) {
544 CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,
545 from, copy_length);
546 }
547 }
548 return REAL(strncat)(to, from, size);
549}
550
551INTERCEPTOR(char *, strcpy, char *to, const char *from) {
552 void *ctx;
553 ASAN_INTERCEPTOR_ENTER(ctx, strcpy);
554 if constexpr (SANITIZER_APPLE) {
555 // strcpy is called from malloc_default_purgeable_zone()
556 // in __asan::ReplaceSystemAlloc() on Mac.
557 if (UNLIKELY(!AsanInited()))
558 return REAL(strcpy)(to, from);
559 } else {
560 if (!TryAsanInitFromRtl())
561 return REAL(strcpy)(to, from);
562 }
563
564 if (flags()->replace_str) {
565 uptr from_size = internal_strlen(s: from) + 1;
566 CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
567 ASAN_READ_RANGE(ctx, from, from_size);
568 ASAN_WRITE_RANGE(ctx, to, from_size);
569 }
570 return REAL(strcpy)(to, from);
571}
572
573// Windows doesn't always define the strdup identifier,
574// and when it does it's a macro defined to either _strdup
575// or _strdup_dbg, _strdup_dbg ends up calling _strdup, so
576// we want to intercept that. push/pop_macro are used to avoid problems
577// if this file ends up including <string.h> in the future.
578# if SANITIZER_WINDOWS
579# pragma push_macro("strdup")
580# undef strdup
581# define strdup _strdup
582# endif
583
584INTERCEPTOR(char*, strdup, const char *s) {
585 void *ctx;
586 ASAN_INTERCEPTOR_ENTER(ctx, strdup);
587 // Allowing null input is Windows-specific
588 if (SANITIZER_WINDOWS && UNLIKELY(!s))
589 return nullptr;
590 if (UNLIKELY(!TryAsanInitFromRtl()))
591 return internal_strdup(s);
592 uptr length = internal_strlen(s);
593 if (flags()->replace_str) {
594 ASAN_READ_RANGE(ctx, s, length + 1);
595 }
596 GET_STACK_TRACE_MALLOC;
597 void *new_mem = asan_malloc(size: length + 1, stack: &stack);
598 if (new_mem) {
599 REAL(memcpy)(new_mem, s, length + 1);
600 }
601 return reinterpret_cast<char*>(new_mem);
602}
603
604# if ASAN_INTERCEPT___STRDUP
605INTERCEPTOR(char*, __strdup, const char *s) {
606 void *ctx;
607 ASAN_INTERCEPTOR_ENTER(ctx, strdup);
608 if (UNLIKELY(!TryAsanInitFromRtl()))
609 return internal_strdup(s);
610 uptr length = internal_strlen(s);
611 if (flags()->replace_str) {
612 ASAN_READ_RANGE(ctx, s, length + 1);
613 }
614 GET_STACK_TRACE_MALLOC;
615 void *new_mem = asan_malloc(size: length + 1, stack: &stack);
616 if (new_mem) {
617 REAL(memcpy)(new_mem, s, length + 1);
618 }
619 return reinterpret_cast<char*>(new_mem);
620}
621#endif // ASAN_INTERCEPT___STRDUP
622
623INTERCEPTOR(char*, strncpy, char *to, const char *from, usize size) {
624 void *ctx;
625 ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
626 AsanInitFromRtl();
627 if (flags()->replace_str) {
628 uptr from_size = Min<uptr>(a: size, b: MaybeRealStrnlen(s: from, maxlen: size) + 1);
629 CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
630 ASAN_READ_RANGE(ctx, from, from_size);
631 ASAN_WRITE_RANGE(ctx, to, size);
632 }
633 return REAL(strncpy)(to, from, size);
634}
635
636template <typename Fn>
637static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr,
638 char **endptr, int base)
639 -> decltype(real(nullptr, nullptr, 0)) {
640 if (!flags()->replace_str)
641 return real(nptr, endptr, base);
642 char *real_endptr;
643 auto res = real(nptr, &real_endptr, base);
644 StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
645 return res;
646}
647
648# define INTERCEPTOR_STRTO_BASE(ret_type, func) \
649 INTERCEPTOR(ret_type, func, const char *nptr, char **endptr, int base) { \
650 void *ctx; \
651 ASAN_INTERCEPTOR_ENTER(ctx, func); \
652 AsanInitFromRtl(); \
653 return StrtolImpl(ctx, REAL(func), nptr, endptr, base); \
654 }
655
656INTERCEPTOR_STRTO_BASE(long long, strtoll)
657
658# if SANITIZER_WINDOWS
659INTERCEPTOR(long, strtol, const char *nptr, char **endptr, int base) {
660 // REAL(strtol) may be ntdll!strtol, which doesn't set errno. Instead,
661 // call REAL(strtoll) and do the range check ourselves.
662 COMPILER_CHECK(sizeof(long) == sizeof(u32));
663
664 void *ctx;
665 ASAN_INTERCEPTOR_ENTER(ctx, strtol);
666 AsanInitFromRtl();
667
668 long long result = StrtolImpl(ctx, REAL(strtoll), nptr, endptr, base);
669
670 if (result > INT32_MAX) {
671 errno = errno_ERANGE;
672 return INT32_MAX;
673 }
674 if (result < INT32_MIN) {
675 errno = errno_ERANGE;
676 return INT32_MIN;
677 }
678 return (long)result;
679}
680# else
681INTERCEPTOR_STRTO_BASE(long, strtol)
682# endif
683
684# if SANITIZER_GLIBC
685INTERCEPTOR_STRTO_BASE(long, __isoc23_strtol)
686INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll)
687# endif
688
689INTERCEPTOR(int, atoi, const char *nptr) {
690 void *ctx;
691 ASAN_INTERCEPTOR_ENTER(ctx, atoi);
692 if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
693 return REAL(atoi)(nptr);
694 AsanInitFromRtl();
695 if (!flags()->replace_str) {
696 return REAL(atoi)(nptr);
697 }
698 char *real_endptr;
699 // "man atoi" tells that behavior of atoi(nptr) is the same as
700 // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the
701 // parsed integer can't be stored in *long* type (even if it's
702 // different from int). So, we just imitate this behavior.
703 int result = REAL(strtol)(nptr, &real_endptr, 10);
704 FixRealStrtolEndptr(nptr, endptr: &real_endptr);
705 ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
706 return result;
707}
708
709INTERCEPTOR(long, atol, const char *nptr) {
710 void *ctx;
711 ASAN_INTERCEPTOR_ENTER(ctx, atol);
712 if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
713 return REAL(atol)(nptr);
714 AsanInitFromRtl();
715 if (!flags()->replace_str) {
716 return REAL(atol)(nptr);
717 }
718 char *real_endptr;
719 long result = REAL(strtol)(nptr, &real_endptr, 10);
720 FixRealStrtolEndptr(nptr, endptr: &real_endptr);
721 ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
722 return result;
723}
724
725INTERCEPTOR(long long, atoll, const char *nptr) {
726 void *ctx;
727 ASAN_INTERCEPTOR_ENTER(ctx, atoll);
728 AsanInitFromRtl();
729 if (!flags()->replace_str) {
730 return REAL(atoll)(nptr);
731 }
732 char *real_endptr;
733 long long result = REAL(strtoll)(nptr, &real_endptr, 10);
734 FixRealStrtolEndptr(nptr, endptr: &real_endptr);
735 ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
736 return result;
737}
738
739#if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT
740static void AtCxaAtexit(void *unused) {
741 (void)unused;
742 StopInitOrderChecking();
743}
744#endif
745
746#if ASAN_INTERCEPT___CXA_ATEXIT
747INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
748 void *dso_handle) {
749 if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
750 return REAL(__cxa_atexit)(func, arg, dso_handle);
751 AsanInitFromRtl();
752# if CAN_SANITIZE_LEAKS
753 __lsan::ScopedInterceptorDisabler disabler;
754#endif
755 int res = REAL(__cxa_atexit)(func, arg, dso_handle);
756 REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
757 return res;
758}
759#endif // ASAN_INTERCEPT___CXA_ATEXIT
760
761#if ASAN_INTERCEPT_ATEXIT
762INTERCEPTOR(int, atexit, void (*func)()) {
763 AsanInitFromRtl();
764# if CAN_SANITIZE_LEAKS
765 __lsan::ScopedInterceptorDisabler disabler;
766#endif
767 // Avoid calling real atexit as it is unreachable on at least on Linux.
768 int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr);
769 REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
770 return res;
771}
772#endif
773
774#if ASAN_INTERCEPT_PTHREAD_ATFORK
775extern "C" {
776extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
777 void (*child)());
778}
779
780INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
781 void (*child)()) {
782#if CAN_SANITIZE_LEAKS
783 __lsan::ScopedInterceptorDisabler disabler;
784#endif
785 // REAL(pthread_atfork) cannot be called due to symbol indirections at least
786 // on NetBSD
787 return _pthread_atfork(prepare, parent, child);
788}
789#endif
790
791#if ASAN_INTERCEPT_VFORK
792DEFINE_REAL(int, vfork,)
793DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,)
794#endif
795
796// ---------------------- InitializeAsanInterceptors ---------------- {{{1
797namespace __asan {
798void InitializeAsanInterceptors() {
799 static bool was_called_once;
800 CHECK(!was_called_once);
801 was_called_once = true;
802 InitializePlatformInterceptors();
803 InitializeCommonInterceptors();
804 InitializeSignalInterceptors();
805
806 // Intercept str* functions.
807 ASAN_INTERCEPT_FUNC(strcat);
808 ASAN_INTERCEPT_FUNC(strcpy);
809 ASAN_INTERCEPT_FUNC(strncat);
810 ASAN_INTERCEPT_FUNC(strncpy);
811 ASAN_INTERCEPT_FUNC(strdup);
812# if ASAN_INTERCEPT___STRDUP
813 ASAN_INTERCEPT_FUNC(__strdup);
814#endif
815#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
816 ASAN_INTERCEPT_FUNC(index);
817#endif
818
819 ASAN_INTERCEPT_FUNC(atoi);
820 ASAN_INTERCEPT_FUNC(atol);
821 ASAN_INTERCEPT_FUNC(atoll);
822 ASAN_INTERCEPT_FUNC(strtol);
823 ASAN_INTERCEPT_FUNC(strtoll);
824# if SANITIZER_GLIBC
825 ASAN_INTERCEPT_FUNC(__isoc23_strtol);
826 ASAN_INTERCEPT_FUNC(__isoc23_strtoll);
827# endif
828
829 // Intercept jump-related functions.
830 ASAN_INTERCEPT_FUNC(longjmp);
831
832# if ASAN_INTERCEPT_SWAPCONTEXT
833 ASAN_INTERCEPT_FUNC(swapcontext);
834 // See the makecontext interceptor above for an explanation.
835# if SANITIZER_SOLARIS && defined(__sparc__)
836 ASAN_INTERCEPT_FUNC(__makecontext_v2);
837# else
838 ASAN_INTERCEPT_FUNC(makecontext);
839# endif
840# endif
841# if ASAN_INTERCEPT__LONGJMP
842 ASAN_INTERCEPT_FUNC(_longjmp);
843#endif
844#if ASAN_INTERCEPT___LONGJMP_CHK
845 ASAN_INTERCEPT_FUNC(__longjmp_chk);
846#endif
847#if ASAN_INTERCEPT_SIGLONGJMP
848 ASAN_INTERCEPT_FUNC(siglongjmp);
849#endif
850
851 // Intercept exception handling functions.
852#if ASAN_INTERCEPT___CXA_THROW
853 ASAN_INTERCEPT_FUNC(__cxa_throw);
854#endif
855#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION
856 ASAN_INTERCEPT_FUNC(__cxa_rethrow_primary_exception);
857#endif
858 // Indirectly intercept std::rethrow_exception.
859#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION
860 ASAN_INTERCEPT_FUNC(_Unwind_RaiseException);
861#endif
862 // Indirectly intercept std::rethrow_exception.
863#if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION
864 ASAN_INTERCEPT_FUNC(_Unwind_SjLj_RaiseException);
865#endif
866
867 // Intercept threading-related functions
868#if ASAN_INTERCEPT_PTHREAD_CREATE
869// TODO: this should probably have an unversioned fallback for newer arches?
870#if defined(ASAN_PTHREAD_CREATE_VERSION)
871 ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION);
872#else
873 ASAN_INTERCEPT_FUNC(pthread_create);
874#endif
875 ASAN_INTERCEPT_FUNC(pthread_join);
876 ASAN_INTERCEPT_FUNC(pthread_detach);
877 ASAN_INTERCEPT_FUNC(pthread_exit);
878# endif
879
880# if ASAN_INTERCEPT_TIMEDJOIN
881 ASAN_INTERCEPT_FUNC(pthread_timedjoin_np);
882#endif
883
884#if ASAN_INTERCEPT_TRYJOIN
885 ASAN_INTERCEPT_FUNC(pthread_tryjoin_np);
886#endif
887
888 // Intercept atexit function.
889#if ASAN_INTERCEPT___CXA_ATEXIT
890 ASAN_INTERCEPT_FUNC(__cxa_atexit);
891#endif
892
893#if ASAN_INTERCEPT_ATEXIT
894 ASAN_INTERCEPT_FUNC(atexit);
895#endif
896
897#if ASAN_INTERCEPT_PTHREAD_ATFORK
898 ASAN_INTERCEPT_FUNC(pthread_atfork);
899#endif
900
901#if ASAN_INTERCEPT_VFORK
902 ASAN_INTERCEPT_FUNC(vfork);
903#endif
904
905 VReport(1, "AddressSanitizer: libc interceptors initialized\n");
906}
907
908# if SANITIZER_WINDOWS
909# pragma pop_macro("strdup")
910# endif
911
912} // namespace __asan
913
914#endif // !SANITIZER_FUCHSIA
915