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(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, uptr)
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(length, GetPageSize());
160    // Only unpoison shadow if it's an ASAN managed address.
161    if (AddrIsInMem(beg) && AddrIsInMem(beg + rounded_length - 1))
162      PoisonShadow(beg, RoundUpTo(length, GetPageSize()), 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(beg, GetPageSize())) {
173    SIZE_T rounded_length = RoundUpTo(length, GetPageSize());
174    // Protect from unmapping the shadow.
175    if (AddrIsInMem(beg) && AddrIsInMem(beg + rounded_length - 1))
176      PoisonShadow(beg, rounded_length, 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(self);
230  t->ThreadStart(GetTid());
231
232#    if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
233        SANITIZER_SOLARIS
234  __sanitizer_sigset_t sigset;
235  t->GetStartData(sigset);
236  SetSigProcMask(&sigset, nullptr);
237#    endif
238
239  thread_return_t retval = (*args.routine)(args.arg_retval);
240  asanThreadArgRetval().Finish(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(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(sigset, current_tid, &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, {start_routine, arg}, [&]() -> 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((uptr)thread, [&]() {
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((uptr)thread, [&]() {
302    result = REAL(pthread_detach)(thread);
303    return !result;
304  });
305  return result;
306}
307
308INTERCEPTOR(void, pthread_exit, void *retval) {
309  asanThreadArgRetval().Finish(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((uptr)thread, [&]() {
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((uptr)thread, [&]() {
329    result = REAL(pthread_timedjoin_np)(thread, ret, abstime);
330    return !result;
331  });
332  return result;
333}
334#    endif
335
336DEFINE_REAL_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(stack, PageSize);
348  if (!AddrIsInMem(bottom))
349    return;
350  ssize += stack - bottom;
351  ssize = RoundUpTo(ssize, PageSize);
352  PoisonShadow(bottom, ssize, 0);
353}
354
355INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc,
356            ...) {
357  va_list ap;
358  uptr args[64];
359  // We don't know a better way to forward ... into REAL function. We can
360  // increase args size if neccecary.
361  CHECK_LE(argc, ARRAY_SIZE(args));
362  internal_memset(args, 0, sizeof(args));
363  va_start(ap, argc);
364  for (int i = 0; i < argc; ++i) args[i] = va_arg(ap, uptr);
365  va_end(ap);
366
367#    define ENUMERATE_ARRAY_4(start) \
368      args[start], args[start + 1], args[start + 2], args[start + 3]
369#    define ENUMERATE_ARRAY_16(start)                         \
370      ENUMERATE_ARRAY_4(start), ENUMERATE_ARRAY_4(start + 4), \
371          ENUMERATE_ARRAY_4(start + 8), ENUMERATE_ARRAY_4(start + 12)
372#    define ENUMERATE_ARRAY_64()                                             \
373      ENUMERATE_ARRAY_16(0), ENUMERATE_ARRAY_16(16), ENUMERATE_ARRAY_16(32), \
374          ENUMERATE_ARRAY_16(48)
375
376  REAL(makecontext)
377  ((struct ucontext_t *)ucp, func, argc, ENUMERATE_ARRAY_64());
378
379#    undef ENUMERATE_ARRAY_4
380#    undef ENUMERATE_ARRAY_16
381#    undef ENUMERATE_ARRAY_64
382
383  // Sign the stack so we can identify it for unpoisoning.
384  SignContextStack(ucp);
385}
386
387INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
388            struct ucontext_t *ucp) {
389  static bool reported_warning = false;
390  if (!reported_warning) {
391    Report("WARNING: ASan doesn't fully support makecontext/swapcontext "
392           "functions and may produce false positives in some cases!\n");
393    reported_warning = true;
394  }
395  // Clear shadow memory for new context (it may share stack
396  // with current context).
397  uptr stack, ssize;
398  ReadContextStack(ucp, &stack, &ssize);
399  ClearShadowMemoryForContextStack(stack, ssize);
400
401#    if __has_attribute(__indirect_return__) && \
402        (defined(__x86_64__) || defined(__i386__))
403  int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *)
404      __attribute__((__indirect_return__)) = REAL(swapcontext);
405  int res = real_swapcontext(oucp, ucp);
406#    else
407  int res = REAL(swapcontext)(oucp, ucp);
408#    endif
409  // swapcontext technically does not return, but program may swap context to
410  // "oucp" later, that would look as if swapcontext() returned 0.
411  // We need to clear shadow for ucp once again, as it may be in arbitrary
412  // state.
413  ClearShadowMemoryForContextStack(stack, ssize);
414  return res;
415}
416#endif  // ASAN_INTERCEPT_SWAPCONTEXT
417
418#if SANITIZER_NETBSD
419#define longjmp __longjmp14
420#define siglongjmp __siglongjmp14
421#endif
422
423INTERCEPTOR(void, longjmp, void *env, int val) {
424  __asan_handle_no_return();
425  REAL(longjmp)(env, val);
426}
427
428#if ASAN_INTERCEPT__LONGJMP
429INTERCEPTOR(void, _longjmp, void *env, int val) {
430  __asan_handle_no_return();
431  REAL(_longjmp)(env, val);
432}
433#endif
434
435#if ASAN_INTERCEPT___LONGJMP_CHK
436INTERCEPTOR(void, __longjmp_chk, void *env, int val) {
437  __asan_handle_no_return();
438  REAL(__longjmp_chk)(env, val);
439}
440#endif
441
442#if ASAN_INTERCEPT_SIGLONGJMP
443INTERCEPTOR(void, siglongjmp, void *env, int val) {
444  __asan_handle_no_return();
445  REAL(siglongjmp)(env, val);
446}
447#endif
448
449#if ASAN_INTERCEPT___CXA_THROW
450INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
451  CHECK(REAL(__cxa_throw));
452  __asan_handle_no_return();
453  REAL(__cxa_throw)(a, b, c);
454}
455#endif
456
457#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION
458INTERCEPTOR(void, __cxa_rethrow_primary_exception, void *a) {
459  CHECK(REAL(__cxa_rethrow_primary_exception));
460  __asan_handle_no_return();
461  REAL(__cxa_rethrow_primary_exception)(a);
462}
463#endif
464
465#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION
466INTERCEPTOR(_Unwind_Reason_Code, _Unwind_RaiseException,
467            _Unwind_Exception *object) {
468  CHECK(REAL(_Unwind_RaiseException));
469  __asan_handle_no_return();
470  return REAL(_Unwind_RaiseException)(object);
471}
472#endif
473
474#if ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION
475INTERCEPTOR(_Unwind_Reason_Code, _Unwind_SjLj_RaiseException,
476            _Unwind_Exception *object) {
477  CHECK(REAL(_Unwind_SjLj_RaiseException));
478  __asan_handle_no_return();
479  return REAL(_Unwind_SjLj_RaiseException)(object);
480}
481#endif
482
483#if ASAN_INTERCEPT_INDEX
484# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
485INTERCEPTOR(char*, index, const char *string, int c)
486  ALIAS(WRAP(strchr));
487# else
488#  if SANITIZER_APPLE
489DECLARE_REAL(char*, index, const char *string, int c)
490OVERRIDE_FUNCTION(index, strchr);
491#  else
492DEFINE_REAL(char*, index, const char *string, int c)
493#  endif
494# endif
495#endif  // ASAN_INTERCEPT_INDEX
496
497// For both strcat() and strncat() we need to check the validity of |to|
498// argument irrespective of the |from| length.
499  INTERCEPTOR(char *, strcat, char *to, const char *from) {
500    void *ctx;
501    ASAN_INTERCEPTOR_ENTER(ctx, strcat);
502    AsanInitFromRtl();
503    if (flags()->replace_str) {
504      uptr from_length = internal_strlen(from);
505      ASAN_READ_RANGE(ctx, from, from_length + 1);
506      uptr to_length = internal_strlen(to);
507      ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
508      ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
509      // If the copying actually happens, the |from| string should not overlap
510      // with the resulting string starting at |to|, which has a length of
511      // to_length + from_length + 1.
512      if (from_length > 0) {
513        CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1, from,
514                             from_length + 1);
515      }
516    }
517    return REAL(strcat)(to, from);
518  }
519
520INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
521  void *ctx;
522  ASAN_INTERCEPTOR_ENTER(ctx, strncat);
523  AsanInitFromRtl();
524  if (flags()->replace_str) {
525    uptr from_length = MaybeRealStrnlen(from, size);
526    uptr copy_length = Min(size, from_length + 1);
527    ASAN_READ_RANGE(ctx, from, copy_length);
528    uptr to_length = internal_strlen(to);
529    ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
530    ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
531    if (from_length > 0) {
532      CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,
533                           from, copy_length);
534    }
535  }
536  return REAL(strncat)(to, from, size);
537}
538
539INTERCEPTOR(char *, strcpy, char *to, const char *from) {
540  void *ctx;
541  ASAN_INTERCEPTOR_ENTER(ctx, strcpy);
542  if constexpr (SANITIZER_APPLE) {
543    // strcpy is called from malloc_default_purgeable_zone()
544    // in __asan::ReplaceSystemAlloc() on Mac.
545    if (UNLIKELY(!AsanInited()))
546      return REAL(strcpy)(to, from);
547  } else {
548    if (!TryAsanInitFromRtl())
549      return REAL(strcpy)(to, from);
550  }
551
552  if (flags()->replace_str) {
553    uptr from_size = internal_strlen(from) + 1;
554    CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
555    ASAN_READ_RANGE(ctx, from, from_size);
556    ASAN_WRITE_RANGE(ctx, to, from_size);
557  }
558  return REAL(strcpy)(to, from);
559}
560
561INTERCEPTOR(char*, strdup, const char *s) {
562  void *ctx;
563  ASAN_INTERCEPTOR_ENTER(ctx, strdup);
564  if (UNLIKELY(!TryAsanInitFromRtl()))
565    return internal_strdup(s);
566  uptr length = internal_strlen(s);
567  if (flags()->replace_str) {
568    ASAN_READ_RANGE(ctx, s, length + 1);
569  }
570  GET_STACK_TRACE_MALLOC;
571  void *new_mem = asan_malloc(length + 1, &stack);
572  if (new_mem) {
573    REAL(memcpy)(new_mem, s, length + 1);
574  }
575  return reinterpret_cast<char*>(new_mem);
576}
577
578#if ASAN_INTERCEPT___STRDUP
579INTERCEPTOR(char*, __strdup, const char *s) {
580  void *ctx;
581  ASAN_INTERCEPTOR_ENTER(ctx, strdup);
582  if (UNLIKELY(!TryAsanInitFromRtl()))
583    return internal_strdup(s);
584  uptr length = internal_strlen(s);
585  if (flags()->replace_str) {
586    ASAN_READ_RANGE(ctx, s, length + 1);
587  }
588  GET_STACK_TRACE_MALLOC;
589  void *new_mem = asan_malloc(length + 1, &stack);
590  if (new_mem) {
591    REAL(memcpy)(new_mem, s, length + 1);
592  }
593  return reinterpret_cast<char*>(new_mem);
594}
595#endif // ASAN_INTERCEPT___STRDUP
596
597INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
598  void *ctx;
599  ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
600  AsanInitFromRtl();
601  if (flags()->replace_str) {
602    uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1);
603    CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
604    ASAN_READ_RANGE(ctx, from, from_size);
605    ASAN_WRITE_RANGE(ctx, to, size);
606  }
607  return REAL(strncpy)(to, from, size);
608}
609
610template <typename Fn>
611static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr,
612                                     char **endptr, int base)
613    -> decltype(real(nullptr, nullptr, 0)) {
614  if (!flags()->replace_str)
615    return real(nptr, endptr, base);
616  char *real_endptr;
617  auto res = real(nptr, &real_endptr, base);
618  StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
619  return res;
620}
621
622#  define INTERCEPTOR_STRTO_BASE(ret_type, func)                             \
623    INTERCEPTOR(ret_type, func, const char *nptr, char **endptr, int base) { \
624      void *ctx;                                                             \
625      ASAN_INTERCEPTOR_ENTER(ctx, func);                                     \
626      AsanInitFromRtl();                                                     \
627      return StrtolImpl(ctx, REAL(func), nptr, endptr, base);                \
628    }
629
630INTERCEPTOR_STRTO_BASE(long, strtol)
631INTERCEPTOR_STRTO_BASE(long long, strtoll)
632
633#  if SANITIZER_GLIBC
634INTERCEPTOR_STRTO_BASE(long, __isoc23_strtol)
635INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll)
636#  endif
637
638INTERCEPTOR(int, atoi, const char *nptr) {
639  void *ctx;
640  ASAN_INTERCEPTOR_ENTER(ctx, atoi);
641  if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
642    return REAL(atoi)(nptr);
643  AsanInitFromRtl();
644  if (!flags()->replace_str) {
645    return REAL(atoi)(nptr);
646  }
647  char *real_endptr;
648  // "man atoi" tells that behavior of atoi(nptr) is the same as
649  // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the
650  // parsed integer can't be stored in *long* type (even if it's
651  // different from int). So, we just imitate this behavior.
652  int result = REAL(strtol)(nptr, &real_endptr, 10);
653  FixRealStrtolEndptr(nptr, &real_endptr);
654  ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
655  return result;
656}
657
658INTERCEPTOR(long, atol, const char *nptr) {
659  void *ctx;
660  ASAN_INTERCEPTOR_ENTER(ctx, atol);
661  if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
662    return REAL(atol)(nptr);
663  AsanInitFromRtl();
664  if (!flags()->replace_str) {
665    return REAL(atol)(nptr);
666  }
667  char *real_endptr;
668  long result = REAL(strtol)(nptr, &real_endptr, 10);
669  FixRealStrtolEndptr(nptr, &real_endptr);
670  ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
671  return result;
672}
673
674INTERCEPTOR(long long, atoll, const char *nptr) {
675  void *ctx;
676  ASAN_INTERCEPTOR_ENTER(ctx, atoll);
677  AsanInitFromRtl();
678  if (!flags()->replace_str) {
679    return REAL(atoll)(nptr);
680  }
681  char *real_endptr;
682  long long result = REAL(strtoll)(nptr, &real_endptr, 10);
683  FixRealStrtolEndptr(nptr, &real_endptr);
684  ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
685  return result;
686}
687
688#if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT
689static void AtCxaAtexit(void *unused) {
690  (void)unused;
691  StopInitOrderChecking();
692}
693#endif
694
695#if ASAN_INTERCEPT___CXA_ATEXIT
696INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
697            void *dso_handle) {
698  if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
699    return REAL(__cxa_atexit)(func, arg, dso_handle);
700  AsanInitFromRtl();
701#    if CAN_SANITIZE_LEAKS
702  __lsan::ScopedInterceptorDisabler disabler;
703#endif
704  int res = REAL(__cxa_atexit)(func, arg, dso_handle);
705  REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
706  return res;
707}
708#endif  // ASAN_INTERCEPT___CXA_ATEXIT
709
710#if ASAN_INTERCEPT_ATEXIT
711INTERCEPTOR(int, atexit, void (*func)()) {
712  AsanInitFromRtl();
713#    if CAN_SANITIZE_LEAKS
714  __lsan::ScopedInterceptorDisabler disabler;
715#endif
716  // Avoid calling real atexit as it is unreachable on at least on Linux.
717  int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr);
718  REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
719  return res;
720}
721#endif
722
723#if ASAN_INTERCEPT_PTHREAD_ATFORK
724extern "C" {
725extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
726                           void (*child)());
727};
728
729INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
730            void (*child)()) {
731#if CAN_SANITIZE_LEAKS
732  __lsan::ScopedInterceptorDisabler disabler;
733#endif
734  // REAL(pthread_atfork) cannot be called due to symbol indirections at least
735  // on NetBSD
736  return _pthread_atfork(prepare, parent, child);
737}
738#endif
739
740#if ASAN_INTERCEPT_VFORK
741DEFINE_REAL(int, vfork)
742DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork)
743#endif
744
745// ---------------------- InitializeAsanInterceptors ---------------- {{{1
746namespace __asan {
747void InitializeAsanInterceptors() {
748  static bool was_called_once;
749  CHECK(!was_called_once);
750  was_called_once = true;
751  InitializePlatformInterceptors();
752  InitializeCommonInterceptors();
753  InitializeSignalInterceptors();
754
755  // Intercept str* functions.
756  ASAN_INTERCEPT_FUNC(strcat);
757  ASAN_INTERCEPT_FUNC(strcpy);
758  ASAN_INTERCEPT_FUNC(strncat);
759  ASAN_INTERCEPT_FUNC(strncpy);
760  ASAN_INTERCEPT_FUNC(strdup);
761#if ASAN_INTERCEPT___STRDUP
762  ASAN_INTERCEPT_FUNC(__strdup);
763#endif
764#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
765  ASAN_INTERCEPT_FUNC(index);
766#endif
767
768  ASAN_INTERCEPT_FUNC(atoi);
769  ASAN_INTERCEPT_FUNC(atol);
770  ASAN_INTERCEPT_FUNC(atoll);
771  ASAN_INTERCEPT_FUNC(strtol);
772  ASAN_INTERCEPT_FUNC(strtoll);
773#  if SANITIZER_GLIBC
774  ASAN_INTERCEPT_FUNC(__isoc23_strtol);
775  ASAN_INTERCEPT_FUNC(__isoc23_strtoll);
776#  endif
777
778  // Intecept jump-related functions.
779  ASAN_INTERCEPT_FUNC(longjmp);
780
781#  if ASAN_INTERCEPT_SWAPCONTEXT
782  ASAN_INTERCEPT_FUNC(swapcontext);
783  ASAN_INTERCEPT_FUNC(makecontext);
784#  endif
785#  if ASAN_INTERCEPT__LONGJMP
786  ASAN_INTERCEPT_FUNC(_longjmp);
787#endif
788#if ASAN_INTERCEPT___LONGJMP_CHK
789  ASAN_INTERCEPT_FUNC(__longjmp_chk);
790#endif
791#if ASAN_INTERCEPT_SIGLONGJMP
792  ASAN_INTERCEPT_FUNC(siglongjmp);
793#endif
794
795  // Intercept exception handling functions.
796#if ASAN_INTERCEPT___CXA_THROW
797  ASAN_INTERCEPT_FUNC(__cxa_throw);
798#endif
799#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION
800  ASAN_INTERCEPT_FUNC(__cxa_rethrow_primary_exception);
801#endif
802  // Indirectly intercept std::rethrow_exception.
803#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION
804  ASAN_INTERCEPT_FUNC(_Unwind_RaiseException);
805#endif
806  // Indirectly intercept std::rethrow_exception.
807#if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION
808  ASAN_INTERCEPT_FUNC(_Unwind_SjLj_RaiseException);
809#endif
810
811  // Intercept threading-related functions
812#if ASAN_INTERCEPT_PTHREAD_CREATE
813// TODO: this should probably have an unversioned fallback for newer arches?
814#if defined(ASAN_PTHREAD_CREATE_VERSION)
815  ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION);
816#else
817  ASAN_INTERCEPT_FUNC(pthread_create);
818#endif
819  ASAN_INTERCEPT_FUNC(pthread_join);
820  ASAN_INTERCEPT_FUNC(pthread_detach);
821  ASAN_INTERCEPT_FUNC(pthread_exit);
822#  endif
823
824#  if ASAN_INTERCEPT_TIMEDJOIN
825  ASAN_INTERCEPT_FUNC(pthread_timedjoin_np);
826#endif
827
828#if ASAN_INTERCEPT_TRYJOIN
829  ASAN_INTERCEPT_FUNC(pthread_tryjoin_np);
830#endif
831
832  // Intercept atexit function.
833#if ASAN_INTERCEPT___CXA_ATEXIT
834  ASAN_INTERCEPT_FUNC(__cxa_atexit);
835#endif
836
837#if ASAN_INTERCEPT_ATEXIT
838  ASAN_INTERCEPT_FUNC(atexit);
839#endif
840
841#if ASAN_INTERCEPT_PTHREAD_ATFORK
842  ASAN_INTERCEPT_FUNC(pthread_atfork);
843#endif
844
845#if ASAN_INTERCEPT_VFORK
846  ASAN_INTERCEPT_FUNC(vfork);
847#endif
848
849  VReport(1, "AddressSanitizer: libc interceptors initialized\n");
850}
851
852} // namespace __asan
853
854#endif  // !SANITIZER_FUCHSIA
855