xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/asan/asan_interceptors.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
168d75effSDimitry Andric //===-- asan_interceptors.cpp ---------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // Intercept various libc functions.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "asan_interceptors.h"
1506c3fb27SDimitry Andric 
1668d75effSDimitry Andric #include "asan_allocator.h"
1768d75effSDimitry Andric #include "asan_internal.h"
1868d75effSDimitry Andric #include "asan_mapping.h"
1968d75effSDimitry Andric #include "asan_poisoning.h"
2068d75effSDimitry Andric #include "asan_report.h"
2168d75effSDimitry Andric #include "asan_stack.h"
2268d75effSDimitry Andric #include "asan_stats.h"
2368d75effSDimitry Andric #include "asan_suppressions.h"
2406c3fb27SDimitry Andric #include "asan_thread.h"
2568d75effSDimitry Andric #include "lsan/lsan_common.h"
2606c3fb27SDimitry Andric #include "sanitizer_common/sanitizer_errno.h"
2706c3fb27SDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h"
2868d75effSDimitry Andric #include "sanitizer_common/sanitizer_libc.h"
2968d75effSDimitry Andric 
30fe6060f1SDimitry Andric // There is no general interception at all on Fuchsia.
3168d75effSDimitry Andric // Only the functions in asan_interceptors_memintrinsics.cpp are
3268d75effSDimitry Andric // really defined to replace libc functions.
33fe6060f1SDimitry Andric #if !SANITIZER_FUCHSIA
3468d75effSDimitry Andric 
3568d75effSDimitry Andric #  if SANITIZER_POSIX
3668d75effSDimitry Andric #    include "sanitizer_common/sanitizer_posix.h"
3768d75effSDimitry Andric #  endif
3868d75effSDimitry Andric 
3968d75effSDimitry Andric #  if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION || \
4068d75effSDimitry Andric       ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION
4168d75effSDimitry Andric #    include <unwind.h>
4268d75effSDimitry Andric #  endif
4368d75effSDimitry Andric 
4468d75effSDimitry Andric #  if defined(__i386) && SANITIZER_LINUX
4568d75effSDimitry Andric #    define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1"
4668d75effSDimitry Andric #  elif defined(__mips__) && SANITIZER_LINUX
4768d75effSDimitry Andric #    define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2"
4868d75effSDimitry Andric #  endif
4968d75effSDimitry Andric 
5068d75effSDimitry Andric namespace __asan {
5168d75effSDimitry Andric 
5268d75effSDimitry Andric #define ASAN_READ_STRING_OF_LEN(ctx, s, len, n)                 \
5368d75effSDimitry Andric   ASAN_READ_RANGE((ctx), (s),                                   \
5468d75effSDimitry Andric     common_flags()->strict_string_checks ? (len) + 1 : (n))
5568d75effSDimitry Andric 
5668d75effSDimitry Andric #  define ASAN_READ_STRING(ctx, s, n) \
57349cc55cSDimitry Andric     ASAN_READ_STRING_OF_LEN((ctx), (s), internal_strlen(s), (n))
5868d75effSDimitry Andric 
5968d75effSDimitry Andric static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
6068d75effSDimitry Andric #if SANITIZER_INTERCEPT_STRNLEN
6168d75effSDimitry Andric   if (REAL(strnlen)) {
6268d75effSDimitry Andric     return REAL(strnlen)(s, maxlen);
6368d75effSDimitry Andric   }
6468d75effSDimitry Andric #endif
6568d75effSDimitry Andric   return internal_strnlen(s, maxlen);
6668d75effSDimitry Andric }
6768d75effSDimitry Andric 
6868d75effSDimitry Andric void SetThreadName(const char *name) {
6968d75effSDimitry Andric   AsanThread *t = GetCurrentThread();
7068d75effSDimitry Andric   if (t)
7168d75effSDimitry Andric     asanThreadRegistry().SetThreadName(t->tid(), name);
7268d75effSDimitry Andric }
7368d75effSDimitry Andric 
7468d75effSDimitry Andric int OnExit() {
7568d75effSDimitry Andric   if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks &&
7668d75effSDimitry Andric       __lsan::HasReportedLeaks()) {
7768d75effSDimitry Andric     return common_flags()->exitcode;
7868d75effSDimitry Andric   }
7968d75effSDimitry Andric   // FIXME: ask frontend whether we need to return failure.
8068d75effSDimitry Andric   return 0;
8168d75effSDimitry Andric }
8268d75effSDimitry Andric 
8368d75effSDimitry Andric } // namespace __asan
8468d75effSDimitry Andric 
8568d75effSDimitry Andric // ---------------------- Wrappers ---------------- {{{1
8668d75effSDimitry Andric using namespace __asan;
8768d75effSDimitry Andric 
8868d75effSDimitry Andric DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
8968d75effSDimitry Andric DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
9068d75effSDimitry Andric 
9168d75effSDimitry Andric #define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \
9268d75effSDimitry Andric   ASAN_INTERCEPT_FUNC_VER(name, ver)
93fe6060f1SDimitry Andric #define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \
94fe6060f1SDimitry Andric   ASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver)
9568d75effSDimitry Andric #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
9668d75effSDimitry Andric   ASAN_WRITE_RANGE(ctx, ptr, size)
9768d75effSDimitry Andric #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
9868d75effSDimitry Andric   ASAN_READ_RANGE(ctx, ptr, size)
9968d75effSDimitry Andric #  define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
10068d75effSDimitry Andric     ASAN_INTERCEPTOR_ENTER(ctx, func);             \
10168d75effSDimitry Andric     do {                                           \
1025f757f3fSDimitry Andric       if constexpr (SANITIZER_APPLE) {             \
1035f757f3fSDimitry Andric         if (UNLIKELY(!AsanInited()))               \
10468d75effSDimitry Andric           return REAL(func)(__VA_ARGS__);          \
1055f757f3fSDimitry Andric       } else {                                     \
1065f757f3fSDimitry Andric         if (!TryAsanInitFromRtl())                 \
10768d75effSDimitry Andric           return REAL(func)(__VA_ARGS__);          \
1085f757f3fSDimitry Andric       }                                            \
10968d75effSDimitry Andric     } while (false)
11068d75effSDimitry Andric #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
11168d75effSDimitry Andric   do {                                            \
11268d75effSDimitry Andric   } while (false)
11368d75effSDimitry Andric #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
11468d75effSDimitry Andric   do {                                         \
11568d75effSDimitry Andric   } while (false)
11668d75effSDimitry Andric #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
11768d75effSDimitry Andric   do {                                         \
11868d75effSDimitry Andric   } while (false)
11968d75effSDimitry Andric #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
12068d75effSDimitry Andric   do {                                                      \
12168d75effSDimitry Andric   } while (false)
12268d75effSDimitry Andric #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
12368d75effSDimitry Andric // Should be asanThreadRegistry().SetThreadNameByUserId(thread, name)
12468d75effSDimitry Andric // But asan does not remember UserId's for threads (pthread_t);
12568d75effSDimitry Andric // and remembers all ever existed threads, so the linear search by UserId
12668d75effSDimitry Andric // can be slow.
12768d75effSDimitry Andric #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
12868d75effSDimitry Andric   do {                                                         \
12968d75effSDimitry Andric   } while (false)
13068d75effSDimitry Andric #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
13168d75effSDimitry Andric // Strict init-order checking is dlopen-hostile:
13268d75effSDimitry Andric // https://github.com/google/sanitizers/issues/178
1334824e7fdSDimitry Andric #  define COMMON_INTERCEPTOR_DLOPEN(filename, flag) \
1344824e7fdSDimitry Andric     ({                                              \
13568d75effSDimitry Andric       if (flags()->strict_init_order)               \
13668d75effSDimitry Andric         StopInitOrderChecking();                    \
13768d75effSDimitry Andric       CheckNoDeepBind(filename, flag);              \
1384824e7fdSDimitry Andric       REAL(dlopen)(filename, flag);                 \
1394824e7fdSDimitry Andric     })
14068d75effSDimitry Andric #  define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
14168d75effSDimitry Andric #  define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)
14268d75effSDimitry Andric #  define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()
1435f757f3fSDimitry Andric #  define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!AsanInited())
14468d75effSDimitry Andric #  define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
14568d75effSDimitry Andric     if (AsanThread *t = GetCurrentThread()) {          \
14668d75effSDimitry Andric       *begin = t->tls_begin();                         \
14768d75effSDimitry Andric       *end = t->tls_end();                             \
14868d75effSDimitry Andric     } else {                                           \
14968d75effSDimitry Andric       *begin = *end = 0;                               \
15068d75effSDimitry Andric     }
15168d75effSDimitry Andric 
15206c3fb27SDimitry Andric template <class Mmap>
15306c3fb27SDimitry Andric static void* mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,
15406c3fb27SDimitry Andric                               int prot, int flags, int fd, OFF64_T offset) {
15506c3fb27SDimitry Andric   void *res = real_mmap(addr, length, prot, flags, fd, offset);
15606c3fb27SDimitry Andric   if (length && res != (void *)-1) {
15706c3fb27SDimitry Andric     const uptr beg = reinterpret_cast<uptr>(res);
15806c3fb27SDimitry Andric     DCHECK(IsAligned(beg, GetPageSize()));
15906c3fb27SDimitry Andric     SIZE_T rounded_length = RoundUpTo(length, GetPageSize());
16006c3fb27SDimitry Andric     // Only unpoison shadow if it's an ASAN managed address.
16106c3fb27SDimitry Andric     if (AddrIsInMem(beg) && AddrIsInMem(beg + rounded_length - 1))
16206c3fb27SDimitry Andric       PoisonShadow(beg, RoundUpTo(length, GetPageSize()), 0);
16306c3fb27SDimitry Andric   }
16406c3fb27SDimitry Andric   return res;
16506c3fb27SDimitry Andric }
16606c3fb27SDimitry Andric 
16706c3fb27SDimitry Andric template <class Munmap>
16806c3fb27SDimitry Andric static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) {
16906c3fb27SDimitry Andric   // We should not tag if munmap fail, but it's to late to tag after
17006c3fb27SDimitry Andric   // real_munmap, as the pages could be mmaped by another thread.
17106c3fb27SDimitry Andric   const uptr beg = reinterpret_cast<uptr>(addr);
17206c3fb27SDimitry Andric   if (length && IsAligned(beg, GetPageSize())) {
17306c3fb27SDimitry Andric     SIZE_T rounded_length = RoundUpTo(length, GetPageSize());
17406c3fb27SDimitry Andric     // Protect from unmapping the shadow.
17506c3fb27SDimitry Andric     if (AddrIsInMem(beg) && AddrIsInMem(beg + rounded_length - 1))
17606c3fb27SDimitry Andric       PoisonShadow(beg, rounded_length, 0);
17706c3fb27SDimitry Andric   }
17806c3fb27SDimitry Andric   return real_munmap(addr, length);
17906c3fb27SDimitry Andric }
18006c3fb27SDimitry Andric 
18106c3fb27SDimitry Andric #  define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags,   \
18206c3fb27SDimitry Andric                                      fd, offset)                               \
18368d75effSDimitry Andric   do {                                                                         \
18406c3fb27SDimitry Andric     (void)(ctx);                                                               \
18506c3fb27SDimitry Andric     return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off);       \
18668d75effSDimitry Andric   } while (false)
18768d75effSDimitry Andric 
18806c3fb27SDimitry Andric #  define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length)                    \
18968d75effSDimitry Andric   do {                                                                         \
19006c3fb27SDimitry Andric     (void)(ctx);                                                               \
19106c3fb27SDimitry Andric     return munmap_interceptor(REAL(munmap), addr, sz);                         \
19268d75effSDimitry Andric   } while (false)
19368d75effSDimitry Andric 
19468d75effSDimitry Andric #if CAN_SANITIZE_LEAKS
19568d75effSDimitry Andric #define COMMON_INTERCEPTOR_STRERROR()                       \
19668d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler
19768d75effSDimitry Andric #endif
19868d75effSDimitry Andric 
1995f757f3fSDimitry Andric #  define SIGNAL_INTERCEPTOR_ENTER() \
2005f757f3fSDimitry Andric     do {                             \
2015f757f3fSDimitry Andric       AsanInitFromRtl();             \
2025f757f3fSDimitry Andric     } while (false)
20306c3fb27SDimitry Andric 
20468d75effSDimitry Andric #  include "sanitizer_common/sanitizer_common_interceptors.inc"
20568d75effSDimitry Andric #  include "sanitizer_common/sanitizer_signal_interceptors.inc"
20668d75effSDimitry Andric 
20768d75effSDimitry Andric // Syscall interceptors don't have contexts, we don't support suppressions
20868d75effSDimitry Andric // for them.
20968d75effSDimitry Andric #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s)
21068d75effSDimitry Andric #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s)
21168d75effSDimitry Andric #define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
21268d75effSDimitry Andric   do {                                       \
21368d75effSDimitry Andric     (void)(p);                               \
21468d75effSDimitry Andric     (void)(s);                               \
21568d75effSDimitry Andric   } while (false)
21668d75effSDimitry Andric #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
21768d75effSDimitry Andric   do {                                        \
21868d75effSDimitry Andric     (void)(p);                                \
21968d75effSDimitry Andric     (void)(s);                                \
22068d75effSDimitry Andric   } while (false)
22168d75effSDimitry Andric #include "sanitizer_common/sanitizer_common_syscalls.inc"
22268d75effSDimitry Andric #include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
22368d75effSDimitry Andric 
22468d75effSDimitry Andric #if ASAN_INTERCEPT_PTHREAD_CREATE
22568d75effSDimitry Andric static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
226e8d8bef9SDimitry Andric   AsanThread *t = (AsanThread *)arg;
22768d75effSDimitry Andric   SetCurrentThread(t);
22806c3fb27SDimitry Andric   auto self = GetThreadSelf();
22906c3fb27SDimitry Andric   auto args = asanThreadArgRetval().GetArgs(self);
2305f757f3fSDimitry Andric   t->ThreadStart(GetTid());
2315f757f3fSDimitry Andric 
2325f757f3fSDimitry Andric #    if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
2335f757f3fSDimitry Andric         SANITIZER_SOLARIS
2345f757f3fSDimitry Andric   __sanitizer_sigset_t sigset;
2355f757f3fSDimitry Andric   t->GetStartData(sigset);
2365f757f3fSDimitry Andric   SetSigProcMask(&sigset, nullptr);
2375f757f3fSDimitry Andric #    endif
2385f757f3fSDimitry Andric 
2395f757f3fSDimitry Andric   thread_return_t retval = (*args.routine)(args.arg_retval);
24006c3fb27SDimitry Andric   asanThreadArgRetval().Finish(self, retval);
24106c3fb27SDimitry Andric   return retval;
24268d75effSDimitry Andric }
24368d75effSDimitry Andric 
24406c3fb27SDimitry Andric INTERCEPTOR(int, pthread_create, void *thread, void *attr,
24506c3fb27SDimitry Andric             void *(*start_routine)(void *), void *arg) {
24668d75effSDimitry Andric   EnsureMainThreadIDIsCorrect();
24768d75effSDimitry Andric   // Strict init-order checking is thread-hostile.
24868d75effSDimitry Andric   if (flags()->strict_init_order)
24968d75effSDimitry Andric     StopInitOrderChecking();
25068d75effSDimitry Andric   GET_STACK_TRACE_THREAD;
25106c3fb27SDimitry Andric   bool detached = [attr]() {
25206c3fb27SDimitry Andric     int d = 0;
25306c3fb27SDimitry Andric     return attr && !REAL(pthread_attr_getdetachstate)(attr, &d) &&
25406c3fb27SDimitry Andric            IsStateDetached(d);
25506c3fb27SDimitry Andric   }();
256e8d8bef9SDimitry Andric 
257e8d8bef9SDimitry Andric   u32 current_tid = GetCurrentTidOrInvalid();
2585f757f3fSDimitry Andric 
2595f757f3fSDimitry Andric   __sanitizer_sigset_t sigset = {};
2605f757f3fSDimitry Andric #    if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
2615f757f3fSDimitry Andric         SANITIZER_SOLARIS
2625f757f3fSDimitry Andric   ScopedBlockSignals block(&sigset);
2635f757f3fSDimitry Andric #    endif
2645f757f3fSDimitry Andric 
2655f757f3fSDimitry Andric   AsanThread *t = AsanThread::Create(sigset, current_tid, &stack, detached);
266e8d8bef9SDimitry Andric 
26768d75effSDimitry Andric   int result;
26868d75effSDimitry Andric   {
26968d75effSDimitry Andric     // Ignore all allocations made by pthread_create: thread stack/TLS may be
27068d75effSDimitry Andric     // stored by pthread for future reuse even after thread destruction, and
27168d75effSDimitry Andric     // the linked list it's stored in doesn't even hold valid pointers to the
27268d75effSDimitry Andric     // objects, the latter are calculated by obscure pointer arithmetic.
27368d75effSDimitry Andric #    if CAN_SANITIZE_LEAKS
27468d75effSDimitry Andric     __lsan::ScopedInterceptorDisabler disabler;
27568d75effSDimitry Andric #    endif
27606c3fb27SDimitry Andric     asanThreadArgRetval().Create(detached, {start_routine, arg}, [&]() -> uptr {
277e8d8bef9SDimitry Andric       result = REAL(pthread_create)(thread, attr, asan_thread_start, t);
27806c3fb27SDimitry Andric       return result ? 0 : *(uptr *)(thread);
27906c3fb27SDimitry Andric     });
28068d75effSDimitry Andric   }
281e8d8bef9SDimitry Andric   if (result != 0) {
282e8d8bef9SDimitry Andric     // If the thread didn't start delete the AsanThread to avoid leaking it.
283e8d8bef9SDimitry Andric     // Note AsanThreadContexts never get destroyed so the AsanThreadContext
284e8d8bef9SDimitry Andric     // that was just created for the AsanThread is wasted.
285e8d8bef9SDimitry Andric     t->Destroy();
28668d75effSDimitry Andric   }
28768d75effSDimitry Andric   return result;
28868d75effSDimitry Andric }
28968d75effSDimitry Andric 
29006c3fb27SDimitry Andric INTERCEPTOR(int, pthread_join, void *thread, void **retval) {
29106c3fb27SDimitry Andric   int result;
29206c3fb27SDimitry Andric   asanThreadArgRetval().Join((uptr)thread, [&]() {
29306c3fb27SDimitry Andric     result = REAL(pthread_join)(thread, retval);
29406c3fb27SDimitry Andric     return !result;
29506c3fb27SDimitry Andric   });
29606c3fb27SDimitry Andric   return result;
29768d75effSDimitry Andric }
29868d75effSDimitry Andric 
29906c3fb27SDimitry Andric INTERCEPTOR(int, pthread_detach, void *thread) {
30006c3fb27SDimitry Andric   int result;
30106c3fb27SDimitry Andric   asanThreadArgRetval().Detach((uptr)thread, [&]() {
30206c3fb27SDimitry Andric     result = REAL(pthread_detach)(thread);
30306c3fb27SDimitry Andric     return !result;
30406c3fb27SDimitry Andric   });
30506c3fb27SDimitry Andric   return result;
30606c3fb27SDimitry Andric }
30706c3fb27SDimitry Andric 
3085f757f3fSDimitry Andric INTERCEPTOR(void, pthread_exit, void *retval) {
30906c3fb27SDimitry Andric   asanThreadArgRetval().Finish(GetThreadSelf(), retval);
3105f757f3fSDimitry Andric   REAL(pthread_exit)(retval);
31106c3fb27SDimitry Andric }
31206c3fb27SDimitry Andric 
31306c3fb27SDimitry Andric #    if ASAN_INTERCEPT_TRYJOIN
31406c3fb27SDimitry Andric INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) {
31506c3fb27SDimitry Andric   int result;
31606c3fb27SDimitry Andric   asanThreadArgRetval().Join((uptr)thread, [&]() {
31706c3fb27SDimitry Andric     result = REAL(pthread_tryjoin_np)(thread, ret);
31806c3fb27SDimitry Andric     return !result;
31906c3fb27SDimitry Andric   });
32006c3fb27SDimitry Andric   return result;
32106c3fb27SDimitry Andric }
32206c3fb27SDimitry Andric #    endif
32306c3fb27SDimitry Andric 
32406c3fb27SDimitry Andric #    if ASAN_INTERCEPT_TIMEDJOIN
32506c3fb27SDimitry Andric INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,
32606c3fb27SDimitry Andric             const struct timespec *abstime) {
32706c3fb27SDimitry Andric   int result;
32806c3fb27SDimitry Andric   asanThreadArgRetval().Join((uptr)thread, [&]() {
32906c3fb27SDimitry Andric     result = REAL(pthread_timedjoin_np)(thread, ret, abstime);
33006c3fb27SDimitry Andric     return !result;
33106c3fb27SDimitry Andric   });
33206c3fb27SDimitry Andric   return result;
33306c3fb27SDimitry Andric }
33406c3fb27SDimitry Andric #    endif
33506c3fb27SDimitry Andric 
336*0fca6ea1SDimitry Andric DEFINE_INTERNAL_PTHREAD_FUNCTIONS
33768d75effSDimitry Andric #endif  // ASAN_INTERCEPT_PTHREAD_CREATE
33868d75effSDimitry Andric 
33968d75effSDimitry Andric #if ASAN_INTERCEPT_SWAPCONTEXT
34068d75effSDimitry Andric static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {
341fcaf7f86SDimitry Andric   // Only clear if we know the stack. This should be true only for contexts
342fcaf7f86SDimitry Andric   // created with makecontext().
343fcaf7f86SDimitry Andric   if (!ssize)
344fcaf7f86SDimitry Andric     return;
34568d75effSDimitry Andric   // Align to page size.
34668d75effSDimitry Andric   uptr PageSize = GetPageSizeCached();
347fcaf7f86SDimitry Andric   uptr bottom = RoundDownTo(stack, PageSize);
348fcaf7f86SDimitry Andric   if (!AddrIsInMem(bottom))
349fcaf7f86SDimitry Andric     return;
35068d75effSDimitry Andric   ssize += stack - bottom;
35168d75effSDimitry Andric   ssize = RoundUpTo(ssize, PageSize);
35268d75effSDimitry Andric   PoisonShadow(bottom, ssize, 0);
35368d75effSDimitry Andric }
35468d75effSDimitry Andric 
355*0fca6ea1SDimitry Andric // Since Solaris 10/SPARC, ucp->uc_stack.ss_sp refers to the stack base address
356*0fca6ea1SDimitry Andric // as on other targets.  For binary compatibility, the new version uses a
357*0fca6ea1SDimitry Andric // different external name, so we intercept that.
358*0fca6ea1SDimitry Andric #    if SANITIZER_SOLARIS && defined(__sparc__)
359*0fca6ea1SDimitry Andric INTERCEPTOR(void, __makecontext_v2, struct ucontext_t *ucp, void (*func)(),
360*0fca6ea1SDimitry Andric             int argc, ...) {
361*0fca6ea1SDimitry Andric #    else
3629e7101a8SDimitry Andric INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc,
3639e7101a8SDimitry Andric             ...) {
364*0fca6ea1SDimitry Andric #    endif
3659e7101a8SDimitry Andric   va_list ap;
3669e7101a8SDimitry Andric   uptr args[64];
3679e7101a8SDimitry Andric   // We don't know a better way to forward ... into REAL function. We can
3689e7101a8SDimitry Andric   // increase args size if neccecary.
3699e7101a8SDimitry Andric   CHECK_LE(argc, ARRAY_SIZE(args));
3709e7101a8SDimitry Andric   internal_memset(args, 0, sizeof(args));
3719e7101a8SDimitry Andric   va_start(ap, argc);
3729e7101a8SDimitry Andric   for (int i = 0; i < argc; ++i) args[i] = va_arg(ap, uptr);
3739e7101a8SDimitry Andric   va_end(ap);
3749e7101a8SDimitry Andric 
3759e7101a8SDimitry Andric #    define ENUMERATE_ARRAY_4(start) \
3769e7101a8SDimitry Andric       args[start], args[start + 1], args[start + 2], args[start + 3]
3779e7101a8SDimitry Andric #    define ENUMERATE_ARRAY_16(start)                         \
3789e7101a8SDimitry Andric       ENUMERATE_ARRAY_4(start), ENUMERATE_ARRAY_4(start + 4), \
3799e7101a8SDimitry Andric           ENUMERATE_ARRAY_4(start + 8), ENUMERATE_ARRAY_4(start + 12)
3809e7101a8SDimitry Andric #    define ENUMERATE_ARRAY_64()                                             \
3819e7101a8SDimitry Andric       ENUMERATE_ARRAY_16(0), ENUMERATE_ARRAY_16(16), ENUMERATE_ARRAY_16(32), \
3829e7101a8SDimitry Andric           ENUMERATE_ARRAY_16(48)
3839e7101a8SDimitry Andric 
384*0fca6ea1SDimitry Andric #    if SANITIZER_SOLARIS && defined(__sparc__)
385*0fca6ea1SDimitry Andric   REAL(__makecontext_v2)
386*0fca6ea1SDimitry Andric #    else
3879e7101a8SDimitry Andric   REAL(makecontext)
388*0fca6ea1SDimitry Andric #    endif
3899e7101a8SDimitry Andric   ((struct ucontext_t *)ucp, func, argc, ENUMERATE_ARRAY_64());
3909e7101a8SDimitry Andric 
3919e7101a8SDimitry Andric #    undef ENUMERATE_ARRAY_4
3929e7101a8SDimitry Andric #    undef ENUMERATE_ARRAY_16
3939e7101a8SDimitry Andric #    undef ENUMERATE_ARRAY_64
3949e7101a8SDimitry Andric 
3959e7101a8SDimitry Andric   // Sign the stack so we can identify it for unpoisoning.
3969e7101a8SDimitry Andric   SignContextStack(ucp);
397fcaf7f86SDimitry Andric }
398fcaf7f86SDimitry Andric 
39968d75effSDimitry Andric INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
40068d75effSDimitry Andric             struct ucontext_t *ucp) {
40168d75effSDimitry Andric   static bool reported_warning = false;
40268d75effSDimitry Andric   if (!reported_warning) {
40368d75effSDimitry Andric     Report("WARNING: ASan doesn't fully support makecontext/swapcontext "
40468d75effSDimitry Andric            "functions and may produce false positives in some cases!\n");
40568d75effSDimitry Andric     reported_warning = true;
40668d75effSDimitry Andric   }
40768d75effSDimitry Andric   // Clear shadow memory for new context (it may share stack
40868d75effSDimitry Andric   // with current context).
40968d75effSDimitry Andric   uptr stack, ssize;
41068d75effSDimitry Andric   ReadContextStack(ucp, &stack, &ssize);
41168d75effSDimitry Andric   ClearShadowMemoryForContextStack(stack, ssize);
412fcaf7f86SDimitry Andric 
41368d75effSDimitry Andric #    if __has_attribute(__indirect_return__) && \
41468d75effSDimitry Andric         (defined(__x86_64__) || defined(__i386__))
41568d75effSDimitry Andric   int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *)
416fcaf7f86SDimitry Andric       __attribute__((__indirect_return__)) = REAL(swapcontext);
41768d75effSDimitry Andric   int res = real_swapcontext(oucp, ucp);
41868d75effSDimitry Andric #    else
41968d75effSDimitry Andric   int res = REAL(swapcontext)(oucp, ucp);
42068d75effSDimitry Andric #    endif
42168d75effSDimitry Andric   // swapcontext technically does not return, but program may swap context to
42268d75effSDimitry Andric   // "oucp" later, that would look as if swapcontext() returned 0.
42368d75effSDimitry Andric   // We need to clear shadow for ucp once again, as it may be in arbitrary
42468d75effSDimitry Andric   // state.
42568d75effSDimitry Andric   ClearShadowMemoryForContextStack(stack, ssize);
42668d75effSDimitry Andric   return res;
42768d75effSDimitry Andric }
42868d75effSDimitry Andric #endif  // ASAN_INTERCEPT_SWAPCONTEXT
42968d75effSDimitry Andric 
43068d75effSDimitry Andric #if SANITIZER_NETBSD
43168d75effSDimitry Andric #define longjmp __longjmp14
43268d75effSDimitry Andric #define siglongjmp __siglongjmp14
43368d75effSDimitry Andric #endif
43468d75effSDimitry Andric 
43568d75effSDimitry Andric INTERCEPTOR(void, longjmp, void *env, int val) {
43668d75effSDimitry Andric   __asan_handle_no_return();
43768d75effSDimitry Andric   REAL(longjmp)(env, val);
43868d75effSDimitry Andric }
43968d75effSDimitry Andric 
44068d75effSDimitry Andric #if ASAN_INTERCEPT__LONGJMP
44168d75effSDimitry Andric INTERCEPTOR(void, _longjmp, void *env, int val) {
44268d75effSDimitry Andric   __asan_handle_no_return();
44368d75effSDimitry Andric   REAL(_longjmp)(env, val);
44468d75effSDimitry Andric }
44568d75effSDimitry Andric #endif
44668d75effSDimitry Andric 
44768d75effSDimitry Andric #if ASAN_INTERCEPT___LONGJMP_CHK
44868d75effSDimitry Andric INTERCEPTOR(void, __longjmp_chk, void *env, int val) {
44968d75effSDimitry Andric   __asan_handle_no_return();
45068d75effSDimitry Andric   REAL(__longjmp_chk)(env, val);
45168d75effSDimitry Andric }
45268d75effSDimitry Andric #endif
45368d75effSDimitry Andric 
45468d75effSDimitry Andric #if ASAN_INTERCEPT_SIGLONGJMP
45568d75effSDimitry Andric INTERCEPTOR(void, siglongjmp, void *env, int val) {
45668d75effSDimitry Andric   __asan_handle_no_return();
45768d75effSDimitry Andric   REAL(siglongjmp)(env, val);
45868d75effSDimitry Andric }
45968d75effSDimitry Andric #endif
46068d75effSDimitry Andric 
46168d75effSDimitry Andric #if ASAN_INTERCEPT___CXA_THROW
46268d75effSDimitry Andric INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
46368d75effSDimitry Andric   CHECK(REAL(__cxa_throw));
46468d75effSDimitry Andric   __asan_handle_no_return();
46568d75effSDimitry Andric   REAL(__cxa_throw)(a, b, c);
46668d75effSDimitry Andric }
46768d75effSDimitry Andric #endif
46868d75effSDimitry Andric 
46968d75effSDimitry Andric #if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION
47068d75effSDimitry Andric INTERCEPTOR(void, __cxa_rethrow_primary_exception, void *a) {
47168d75effSDimitry Andric   CHECK(REAL(__cxa_rethrow_primary_exception));
47268d75effSDimitry Andric   __asan_handle_no_return();
47368d75effSDimitry Andric   REAL(__cxa_rethrow_primary_exception)(a);
47468d75effSDimitry Andric }
47568d75effSDimitry Andric #endif
47668d75effSDimitry Andric 
47768d75effSDimitry Andric #if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION
47868d75effSDimitry Andric INTERCEPTOR(_Unwind_Reason_Code, _Unwind_RaiseException,
47968d75effSDimitry Andric             _Unwind_Exception *object) {
48068d75effSDimitry Andric   CHECK(REAL(_Unwind_RaiseException));
48168d75effSDimitry Andric   __asan_handle_no_return();
48268d75effSDimitry Andric   return REAL(_Unwind_RaiseException)(object);
48368d75effSDimitry Andric }
48468d75effSDimitry Andric #endif
48568d75effSDimitry Andric 
48668d75effSDimitry Andric #if ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION
48768d75effSDimitry Andric INTERCEPTOR(_Unwind_Reason_Code, _Unwind_SjLj_RaiseException,
48868d75effSDimitry Andric             _Unwind_Exception *object) {
48968d75effSDimitry Andric   CHECK(REAL(_Unwind_SjLj_RaiseException));
49068d75effSDimitry Andric   __asan_handle_no_return();
49168d75effSDimitry Andric   return REAL(_Unwind_SjLj_RaiseException)(object);
49268d75effSDimitry Andric }
49368d75effSDimitry Andric #endif
49468d75effSDimitry Andric 
49568d75effSDimitry Andric #if ASAN_INTERCEPT_INDEX
49668d75effSDimitry Andric # if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
49768d75effSDimitry Andric INTERCEPTOR(char*, index, const char *string, int c)
49806c3fb27SDimitry Andric   ALIAS(WRAP(strchr));
49968d75effSDimitry Andric # else
50081ad6265SDimitry Andric #  if SANITIZER_APPLE
50168d75effSDimitry Andric DECLARE_REAL(char*, index, const char *string, int c)
50268d75effSDimitry Andric OVERRIDE_FUNCTION(index, strchr);
50368d75effSDimitry Andric #  else
50468d75effSDimitry Andric DEFINE_REAL(char*, index, const char *string, int c)
50568d75effSDimitry Andric #  endif
50668d75effSDimitry Andric # endif
50768d75effSDimitry Andric #endif  // ASAN_INTERCEPT_INDEX
50868d75effSDimitry Andric 
50968d75effSDimitry Andric // For both strcat() and strncat() we need to check the validity of |to|
51068d75effSDimitry Andric // argument irrespective of the |from| length.
51168d75effSDimitry Andric   INTERCEPTOR(char *, strcat, char *to, const char *from) {
51268d75effSDimitry Andric     void *ctx;
51368d75effSDimitry Andric     ASAN_INTERCEPTOR_ENTER(ctx, strcat);
5145f757f3fSDimitry Andric     AsanInitFromRtl();
51568d75effSDimitry Andric     if (flags()->replace_str) {
516349cc55cSDimitry Andric       uptr from_length = internal_strlen(from);
51768d75effSDimitry Andric       ASAN_READ_RANGE(ctx, from, from_length + 1);
518349cc55cSDimitry Andric       uptr to_length = internal_strlen(to);
51968d75effSDimitry Andric       ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
52068d75effSDimitry Andric       ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
52168d75effSDimitry Andric       // If the copying actually happens, the |from| string should not overlap
52268d75effSDimitry Andric       // with the resulting string starting at |to|, which has a length of
52368d75effSDimitry Andric       // to_length + from_length + 1.
52468d75effSDimitry Andric       if (from_length > 0) {
52568d75effSDimitry Andric         CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1, from,
52668d75effSDimitry Andric                              from_length + 1);
52768d75effSDimitry Andric       }
52868d75effSDimitry Andric     }
52968d75effSDimitry Andric     return REAL(strcat)(to, from);
53068d75effSDimitry Andric   }
53168d75effSDimitry Andric 
53268d75effSDimitry Andric INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
53368d75effSDimitry Andric   void *ctx;
53468d75effSDimitry Andric   ASAN_INTERCEPTOR_ENTER(ctx, strncat);
5355f757f3fSDimitry Andric   AsanInitFromRtl();
53668d75effSDimitry Andric   if (flags()->replace_str) {
53768d75effSDimitry Andric     uptr from_length = MaybeRealStrnlen(from, size);
53868d75effSDimitry Andric     uptr copy_length = Min(size, from_length + 1);
53968d75effSDimitry Andric     ASAN_READ_RANGE(ctx, from, copy_length);
540349cc55cSDimitry Andric     uptr to_length = internal_strlen(to);
54168d75effSDimitry Andric     ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
54268d75effSDimitry Andric     ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
54368d75effSDimitry Andric     if (from_length > 0) {
54468d75effSDimitry Andric       CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,
54568d75effSDimitry Andric                            from, copy_length);
54668d75effSDimitry Andric     }
54768d75effSDimitry Andric   }
54868d75effSDimitry Andric   return REAL(strncat)(to, from, size);
54968d75effSDimitry Andric }
55068d75effSDimitry Andric 
55168d75effSDimitry Andric INTERCEPTOR(char *, strcpy, char *to, const char *from) {
55268d75effSDimitry Andric   void *ctx;
55368d75effSDimitry Andric   ASAN_INTERCEPTOR_ENTER(ctx, strcpy);
5545f757f3fSDimitry Andric   if constexpr (SANITIZER_APPLE) {
55568d75effSDimitry Andric     // strcpy is called from malloc_default_purgeable_zone()
55668d75effSDimitry Andric     // in __asan::ReplaceSystemAlloc() on Mac.
5575f757f3fSDimitry Andric     if (UNLIKELY(!AsanInited()))
5585f757f3fSDimitry Andric       return REAL(strcpy)(to, from);
5595f757f3fSDimitry Andric   } else {
5605f757f3fSDimitry Andric     if (!TryAsanInitFromRtl())
56168d75effSDimitry Andric       return REAL(strcpy)(to, from);
56268d75effSDimitry Andric   }
5635f757f3fSDimitry Andric 
56468d75effSDimitry Andric   if (flags()->replace_str) {
565349cc55cSDimitry Andric     uptr from_size = internal_strlen(from) + 1;
56668d75effSDimitry Andric     CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
56768d75effSDimitry Andric     ASAN_READ_RANGE(ctx, from, from_size);
56868d75effSDimitry Andric     ASAN_WRITE_RANGE(ctx, to, from_size);
56968d75effSDimitry Andric   }
57068d75effSDimitry Andric   return REAL(strcpy)(to, from);
57168d75effSDimitry Andric }
57268d75effSDimitry Andric 
573*0fca6ea1SDimitry Andric // Windows doesn't always define the strdup identifier,
574*0fca6ea1SDimitry Andric // and when it does it's a macro defined to either _strdup
575*0fca6ea1SDimitry Andric // or _strdup_dbg, _strdup_dbg ends up calling _strdup, so
576*0fca6ea1SDimitry Andric // we want to intercept that. push/pop_macro are used to avoid problems
577*0fca6ea1SDimitry Andric // if this file ends up including <string.h> in the future.
578*0fca6ea1SDimitry Andric #  if SANITIZER_WINDOWS
579*0fca6ea1SDimitry Andric #    pragma push_macro("strdup")
580*0fca6ea1SDimitry Andric #    undef strdup
581*0fca6ea1SDimitry Andric #    define strdup _strdup
582*0fca6ea1SDimitry Andric #  endif
583*0fca6ea1SDimitry Andric 
58468d75effSDimitry Andric INTERCEPTOR(char*, strdup, const char *s) {
58568d75effSDimitry Andric   void *ctx;
58668d75effSDimitry Andric   ASAN_INTERCEPTOR_ENTER(ctx, strdup);
5875f757f3fSDimitry Andric   if (UNLIKELY(!TryAsanInitFromRtl()))
5885f757f3fSDimitry Andric     return internal_strdup(s);
589349cc55cSDimitry Andric   uptr length = internal_strlen(s);
59068d75effSDimitry Andric   if (flags()->replace_str) {
59168d75effSDimitry Andric     ASAN_READ_RANGE(ctx, s, length + 1);
59268d75effSDimitry Andric   }
59368d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
59468d75effSDimitry Andric   void *new_mem = asan_malloc(length + 1, &stack);
59506c3fb27SDimitry Andric   if (new_mem) {
59668d75effSDimitry Andric     REAL(memcpy)(new_mem, s, length + 1);
59706c3fb27SDimitry Andric   }
59868d75effSDimitry Andric   return reinterpret_cast<char*>(new_mem);
59968d75effSDimitry Andric }
60068d75effSDimitry Andric 
60168d75effSDimitry Andric #  if ASAN_INTERCEPT___STRDUP
60268d75effSDimitry Andric INTERCEPTOR(char*, __strdup, const char *s) {
60368d75effSDimitry Andric   void *ctx;
60468d75effSDimitry Andric   ASAN_INTERCEPTOR_ENTER(ctx, strdup);
6055f757f3fSDimitry Andric   if (UNLIKELY(!TryAsanInitFromRtl()))
6065f757f3fSDimitry Andric     return internal_strdup(s);
607349cc55cSDimitry Andric   uptr length = internal_strlen(s);
60868d75effSDimitry Andric   if (flags()->replace_str) {
60968d75effSDimitry Andric     ASAN_READ_RANGE(ctx, s, length + 1);
61068d75effSDimitry Andric   }
61168d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
61268d75effSDimitry Andric   void *new_mem = asan_malloc(length + 1, &stack);
61306c3fb27SDimitry Andric   if (new_mem) {
61468d75effSDimitry Andric     REAL(memcpy)(new_mem, s, length + 1);
61506c3fb27SDimitry Andric   }
61668d75effSDimitry Andric   return reinterpret_cast<char*>(new_mem);
61768d75effSDimitry Andric }
61868d75effSDimitry Andric #endif // ASAN_INTERCEPT___STRDUP
61968d75effSDimitry Andric 
62068d75effSDimitry Andric INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
62168d75effSDimitry Andric   void *ctx;
62268d75effSDimitry Andric   ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
6235f757f3fSDimitry Andric   AsanInitFromRtl();
62468d75effSDimitry Andric   if (flags()->replace_str) {
62568d75effSDimitry Andric     uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1);
62668d75effSDimitry Andric     CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
62768d75effSDimitry Andric     ASAN_READ_RANGE(ctx, from, from_size);
62868d75effSDimitry Andric     ASAN_WRITE_RANGE(ctx, to, size);
62968d75effSDimitry Andric   }
63068d75effSDimitry Andric   return REAL(strncpy)(to, from, size);
63168d75effSDimitry Andric }
63268d75effSDimitry Andric 
6338a4dda33SDimitry Andric template <typename Fn>
6348a4dda33SDimitry Andric static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr,
6358a4dda33SDimitry Andric                                      char **endptr, int base)
6368a4dda33SDimitry Andric     -> decltype(real(nullptr, nullptr, 0)) {
6378a4dda33SDimitry Andric   if (!flags()->replace_str)
6388a4dda33SDimitry Andric     return real(nptr, endptr, base);
63968d75effSDimitry Andric   char *real_endptr;
6408a4dda33SDimitry Andric   auto res = real(nptr, &real_endptr, base);
64168d75effSDimitry Andric   StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
6428a4dda33SDimitry Andric   return res;
64368d75effSDimitry Andric }
64468d75effSDimitry Andric 
6458a4dda33SDimitry Andric #  define INTERCEPTOR_STRTO_BASE(ret_type, func)                             \
6468a4dda33SDimitry Andric     INTERCEPTOR(ret_type, func, const char *nptr, char **endptr, int base) { \
6478a4dda33SDimitry Andric       void *ctx;                                                             \
6488a4dda33SDimitry Andric       ASAN_INTERCEPTOR_ENTER(ctx, func);                                     \
6495f757f3fSDimitry Andric       AsanInitFromRtl();                                                     \
6508a4dda33SDimitry Andric       return StrtolImpl(ctx, REAL(func), nptr, endptr, base);                \
6518a4dda33SDimitry Andric     }
6528a4dda33SDimitry Andric 
6538a4dda33SDimitry Andric INTERCEPTOR_STRTO_BASE(long, strtol)
6548a4dda33SDimitry Andric INTERCEPTOR_STRTO_BASE(long long, strtoll)
6558a4dda33SDimitry Andric 
6568a4dda33SDimitry Andric #  if SANITIZER_GLIBC
6578a4dda33SDimitry Andric INTERCEPTOR_STRTO_BASE(long, __isoc23_strtol)
6588a4dda33SDimitry Andric INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll)
6598a4dda33SDimitry Andric #  endif
6608a4dda33SDimitry Andric 
66168d75effSDimitry Andric INTERCEPTOR(int, atoi, const char *nptr) {
66268d75effSDimitry Andric   void *ctx;
66368d75effSDimitry Andric   ASAN_INTERCEPTOR_ENTER(ctx, atoi);
6645f757f3fSDimitry Andric   if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
6655f757f3fSDimitry Andric     return REAL(atoi)(nptr);
6665f757f3fSDimitry Andric   AsanInitFromRtl();
66768d75effSDimitry Andric   if (!flags()->replace_str) {
66868d75effSDimitry Andric     return REAL(atoi)(nptr);
66968d75effSDimitry Andric   }
67068d75effSDimitry Andric   char *real_endptr;
67168d75effSDimitry Andric   // "man atoi" tells that behavior of atoi(nptr) is the same as
67268d75effSDimitry Andric   // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the
67368d75effSDimitry Andric   // parsed integer can't be stored in *long* type (even if it's
67468d75effSDimitry Andric   // different from int). So, we just imitate this behavior.
67568d75effSDimitry Andric   int result = REAL(strtol)(nptr, &real_endptr, 10);
67668d75effSDimitry Andric   FixRealStrtolEndptr(nptr, &real_endptr);
67768d75effSDimitry Andric   ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
67868d75effSDimitry Andric   return result;
67968d75effSDimitry Andric }
68068d75effSDimitry Andric 
68168d75effSDimitry Andric INTERCEPTOR(long, atol, const char *nptr) {
68268d75effSDimitry Andric   void *ctx;
68368d75effSDimitry Andric   ASAN_INTERCEPTOR_ENTER(ctx, atol);
6845f757f3fSDimitry Andric   if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
6855f757f3fSDimitry Andric     return REAL(atol)(nptr);
6865f757f3fSDimitry Andric   AsanInitFromRtl();
68768d75effSDimitry Andric   if (!flags()->replace_str) {
68868d75effSDimitry Andric     return REAL(atol)(nptr);
68968d75effSDimitry Andric   }
69068d75effSDimitry Andric   char *real_endptr;
69168d75effSDimitry Andric   long result = REAL(strtol)(nptr, &real_endptr, 10);
69268d75effSDimitry Andric   FixRealStrtolEndptr(nptr, &real_endptr);
69368d75effSDimitry Andric   ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
69468d75effSDimitry Andric   return result;
69568d75effSDimitry Andric }
69668d75effSDimitry Andric 
69768d75effSDimitry Andric INTERCEPTOR(long long, atoll, const char *nptr) {
69868d75effSDimitry Andric   void *ctx;
69968d75effSDimitry Andric   ASAN_INTERCEPTOR_ENTER(ctx, atoll);
7005f757f3fSDimitry Andric   AsanInitFromRtl();
70168d75effSDimitry Andric   if (!flags()->replace_str) {
70268d75effSDimitry Andric     return REAL(atoll)(nptr);
70368d75effSDimitry Andric   }
70468d75effSDimitry Andric   char *real_endptr;
70568d75effSDimitry Andric   long long result = REAL(strtoll)(nptr, &real_endptr, 10);
70668d75effSDimitry Andric   FixRealStrtolEndptr(nptr, &real_endptr);
70768d75effSDimitry Andric   ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
70868d75effSDimitry Andric   return result;
70968d75effSDimitry Andric }
71068d75effSDimitry Andric 
71168d75effSDimitry Andric #if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT
71268d75effSDimitry Andric static void AtCxaAtexit(void *unused) {
71368d75effSDimitry Andric   (void)unused;
71468d75effSDimitry Andric   StopInitOrderChecking();
71568d75effSDimitry Andric }
71668d75effSDimitry Andric #endif
71768d75effSDimitry Andric 
71868d75effSDimitry Andric #if ASAN_INTERCEPT___CXA_ATEXIT
71968d75effSDimitry Andric INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
72068d75effSDimitry Andric             void *dso_handle) {
7215f757f3fSDimitry Andric   if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
7225f757f3fSDimitry Andric     return REAL(__cxa_atexit)(func, arg, dso_handle);
7235f757f3fSDimitry Andric   AsanInitFromRtl();
72468d75effSDimitry Andric #    if CAN_SANITIZE_LEAKS
72568d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
72668d75effSDimitry Andric #endif
72768d75effSDimitry Andric   int res = REAL(__cxa_atexit)(func, arg, dso_handle);
72868d75effSDimitry Andric   REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
72968d75effSDimitry Andric   return res;
73068d75effSDimitry Andric }
73168d75effSDimitry Andric #endif  // ASAN_INTERCEPT___CXA_ATEXIT
73268d75effSDimitry Andric 
73368d75effSDimitry Andric #if ASAN_INTERCEPT_ATEXIT
73468d75effSDimitry Andric INTERCEPTOR(int, atexit, void (*func)()) {
7355f757f3fSDimitry Andric   AsanInitFromRtl();
73668d75effSDimitry Andric #    if CAN_SANITIZE_LEAKS
73768d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
73868d75effSDimitry Andric #endif
739349cc55cSDimitry Andric   // Avoid calling real atexit as it is unreachable on at least on Linux.
74068d75effSDimitry Andric   int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr);
74168d75effSDimitry Andric   REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
74268d75effSDimitry Andric   return res;
74368d75effSDimitry Andric }
74468d75effSDimitry Andric #endif
74568d75effSDimitry Andric 
74668d75effSDimitry Andric #if ASAN_INTERCEPT_PTHREAD_ATFORK
74768d75effSDimitry Andric extern "C" {
74868d75effSDimitry Andric extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
74968d75effSDimitry Andric                            void (*child)());
750*0fca6ea1SDimitry Andric }
75168d75effSDimitry Andric 
75268d75effSDimitry Andric INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
75368d75effSDimitry Andric             void (*child)()) {
75468d75effSDimitry Andric #if CAN_SANITIZE_LEAKS
75568d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
75668d75effSDimitry Andric #endif
75768d75effSDimitry Andric   // REAL(pthread_atfork) cannot be called due to symbol indirections at least
75868d75effSDimitry Andric   // on NetBSD
75968d75effSDimitry Andric   return _pthread_atfork(prepare, parent, child);
76068d75effSDimitry Andric }
76168d75effSDimitry Andric #endif
76268d75effSDimitry Andric 
76368d75effSDimitry Andric #if ASAN_INTERCEPT_VFORK
764*0fca6ea1SDimitry Andric DEFINE_REAL(int, vfork,)
765*0fca6ea1SDimitry Andric DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,)
76668d75effSDimitry Andric #endif
76768d75effSDimitry Andric 
76868d75effSDimitry Andric // ---------------------- InitializeAsanInterceptors ---------------- {{{1
76968d75effSDimitry Andric namespace __asan {
77068d75effSDimitry Andric void InitializeAsanInterceptors() {
77168d75effSDimitry Andric   static bool was_called_once;
77268d75effSDimitry Andric   CHECK(!was_called_once);
77368d75effSDimitry Andric   was_called_once = true;
77406c3fb27SDimitry Andric   InitializePlatformInterceptors();
77568d75effSDimitry Andric   InitializeCommonInterceptors();
77668d75effSDimitry Andric   InitializeSignalInterceptors();
77768d75effSDimitry Andric 
77868d75effSDimitry Andric   // Intercept str* functions.
77968d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(strcat);
78068d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(strcpy);
78168d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(strncat);
78268d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(strncpy);
78368d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(strdup);
78468d75effSDimitry Andric #  if ASAN_INTERCEPT___STRDUP
78568d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(__strdup);
78668d75effSDimitry Andric #endif
78768d75effSDimitry Andric #if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
78868d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(index);
78968d75effSDimitry Andric #endif
79068d75effSDimitry Andric 
79168d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(atoi);
79268d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(atol);
79368d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(atoll);
7948a4dda33SDimitry Andric   ASAN_INTERCEPT_FUNC(strtol);
79568d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(strtoll);
7968a4dda33SDimitry Andric #  if SANITIZER_GLIBC
7978a4dda33SDimitry Andric   ASAN_INTERCEPT_FUNC(__isoc23_strtol);
7988a4dda33SDimitry Andric   ASAN_INTERCEPT_FUNC(__isoc23_strtoll);
79968d75effSDimitry Andric #  endif
80068d75effSDimitry Andric 
80168d75effSDimitry Andric   // Intecept jump-related functions.
80268d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(longjmp);
80368d75effSDimitry Andric 
80468d75effSDimitry Andric #  if ASAN_INTERCEPT_SWAPCONTEXT
80568d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(swapcontext);
806*0fca6ea1SDimitry Andric   // See the makecontext interceptor above for an explanation.
807*0fca6ea1SDimitry Andric #    if SANITIZER_SOLARIS && defined(__sparc__)
808*0fca6ea1SDimitry Andric   ASAN_INTERCEPT_FUNC(__makecontext_v2);
809*0fca6ea1SDimitry Andric #    else
8109e7101a8SDimitry Andric   ASAN_INTERCEPT_FUNC(makecontext);
81168d75effSDimitry Andric #    endif
812*0fca6ea1SDimitry Andric #  endif
81368d75effSDimitry Andric #  if ASAN_INTERCEPT__LONGJMP
81468d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(_longjmp);
81568d75effSDimitry Andric #endif
81668d75effSDimitry Andric #if ASAN_INTERCEPT___LONGJMP_CHK
81768d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(__longjmp_chk);
81868d75effSDimitry Andric #endif
81968d75effSDimitry Andric #if ASAN_INTERCEPT_SIGLONGJMP
82068d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(siglongjmp);
82168d75effSDimitry Andric #endif
82268d75effSDimitry Andric 
82368d75effSDimitry Andric   // Intercept exception handling functions.
82468d75effSDimitry Andric #if ASAN_INTERCEPT___CXA_THROW
82568d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(__cxa_throw);
82668d75effSDimitry Andric #endif
82768d75effSDimitry Andric #if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION
82868d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(__cxa_rethrow_primary_exception);
82968d75effSDimitry Andric #endif
83068d75effSDimitry Andric   // Indirectly intercept std::rethrow_exception.
83168d75effSDimitry Andric #if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION
83206c3fb27SDimitry Andric   ASAN_INTERCEPT_FUNC(_Unwind_RaiseException);
83368d75effSDimitry Andric #endif
83468d75effSDimitry Andric   // Indirectly intercept std::rethrow_exception.
83568d75effSDimitry Andric #if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION
83606c3fb27SDimitry Andric   ASAN_INTERCEPT_FUNC(_Unwind_SjLj_RaiseException);
83768d75effSDimitry Andric #endif
83868d75effSDimitry Andric 
83968d75effSDimitry Andric   // Intercept threading-related functions
84068d75effSDimitry Andric #if ASAN_INTERCEPT_PTHREAD_CREATE
841fe6060f1SDimitry Andric // TODO: this should probably have an unversioned fallback for newer arches?
84268d75effSDimitry Andric #if defined(ASAN_PTHREAD_CREATE_VERSION)
84368d75effSDimitry Andric   ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION);
84468d75effSDimitry Andric #else
84568d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(pthread_create);
84668d75effSDimitry Andric #endif
84768d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(pthread_join);
84806c3fb27SDimitry Andric   ASAN_INTERCEPT_FUNC(pthread_detach);
84906c3fb27SDimitry Andric   ASAN_INTERCEPT_FUNC(pthread_exit);
85006c3fb27SDimitry Andric #  endif
85106c3fb27SDimitry Andric 
85206c3fb27SDimitry Andric #  if ASAN_INTERCEPT_TIMEDJOIN
85306c3fb27SDimitry Andric   ASAN_INTERCEPT_FUNC(pthread_timedjoin_np);
85406c3fb27SDimitry Andric #endif
85506c3fb27SDimitry Andric 
85606c3fb27SDimitry Andric #if ASAN_INTERCEPT_TRYJOIN
85706c3fb27SDimitry Andric   ASAN_INTERCEPT_FUNC(pthread_tryjoin_np);
85868d75effSDimitry Andric #endif
85968d75effSDimitry Andric 
86068d75effSDimitry Andric   // Intercept atexit function.
86168d75effSDimitry Andric #if ASAN_INTERCEPT___CXA_ATEXIT
86268d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(__cxa_atexit);
86368d75effSDimitry Andric #endif
86468d75effSDimitry Andric 
86568d75effSDimitry Andric #if ASAN_INTERCEPT_ATEXIT
86668d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(atexit);
86768d75effSDimitry Andric #endif
86868d75effSDimitry Andric 
86968d75effSDimitry Andric #if ASAN_INTERCEPT_PTHREAD_ATFORK
87068d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(pthread_atfork);
87168d75effSDimitry Andric #endif
87268d75effSDimitry Andric 
87368d75effSDimitry Andric #if ASAN_INTERCEPT_VFORK
87468d75effSDimitry Andric   ASAN_INTERCEPT_FUNC(vfork);
87568d75effSDimitry Andric #endif
87668d75effSDimitry Andric 
87768d75effSDimitry Andric   VReport(1, "AddressSanitizer: libc interceptors initialized\n");
87868d75effSDimitry Andric }
87968d75effSDimitry Andric 
880*0fca6ea1SDimitry Andric #  if SANITIZER_WINDOWS
881*0fca6ea1SDimitry Andric #    pragma pop_macro("strdup")
882*0fca6ea1SDimitry Andric #  endif
883*0fca6ea1SDimitry Andric 
88468d75effSDimitry Andric } // namespace __asan
88568d75effSDimitry Andric 
88668d75effSDimitry Andric #endif  // !SANITIZER_FUCHSIA
887