brintos

brintos / llvm-project-archived public Read only

0
0
Text · 30.6 KiB · 8643271 Raw
955 lines · cpp
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-exception6//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 are32// really defined to replace libc functions.33#if !SANITIZER_FUCHSIA34 35#  if SANITIZER_POSIX36#    include "sanitizer_common/sanitizer_posix.h"37#  endif38 39#  if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION || \40      ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION41#    include <unwind.h>42#  endif43 44#  if defined(__i386) && SANITIZER_LINUX45#    define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1"46#  elif defined(__mips__) && SANITIZER_LINUX47#    define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2"48#  endif49 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_STRNLEN61  if (static_cast<bool>(REAL(strnlen)))62    return REAL(strnlen)(s, maxlen);63#  endif64  return internal_strnlen(s, maxlen);65}66 67static inline uptr MaybeRealWcsnlen(const wchar_t* s, uptr maxlen) {68#  if SANITIZER_INTERCEPT_WCSNLEN69  if (static_cast<bool>(REAL(wcsnlen)))70    return REAL(wcsnlen)(s, maxlen);71#  endif72  return internal_wcsnlen(s, maxlen);73}74 75void SetThreadName(const char *name) {76  AsanThread *t = GetCurrentThread();77  if (t)78    asanThreadRegistry().SetThreadName(t->tid(), name);79}80 81int OnExit() {82  if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks &&83      __lsan::HasReportedLeaks()) {84    return common_flags()->exitcode;85  }86  // FIXME: ask frontend whether we need to return failure.87  return 0;88}89 90} // namespace __asan91 92// ---------------------- Wrappers ---------------- {{{193using namespace __asan;94 95DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, usize)96DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)97 98#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \99  ASAN_INTERCEPT_FUNC_VER(name, ver)100#define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \101  ASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver)102#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \103  ASAN_WRITE_RANGE(ctx, ptr, size)104#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \105  ASAN_READ_RANGE(ctx, ptr, size)106#  define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \107    ASAN_INTERCEPTOR_ENTER(ctx, func);             \108    do {                                           \109      if constexpr (SANITIZER_APPLE) {             \110        if (UNLIKELY(!AsanInited()))               \111          return REAL(func)(__VA_ARGS__);          \112      } else {                                     \113        if (!TryAsanInitFromRtl())                 \114          return REAL(func)(__VA_ARGS__);          \115      }                                            \116    } while (false)117#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \118  do {                                            \119  } while (false)120#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \121  do {                                         \122  } while (false)123#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \124  do {                                         \125  } while (false)126#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \127  do {                                                      \128  } while (false)129#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)130// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name)131// But asan does not remember UserId's for threads (pthread_t);132// and remembers all ever existed threads, so the linear search by UserId133// can be slow.134#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \135  do {                                                         \136  } while (false)137#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)138// Strict init-order checking is dlopen-hostile:139// https://github.com/google/sanitizers/issues/178140#  define COMMON_INTERCEPTOR_DLOPEN(filename, flag) \141    ({                                              \142      if (flags()->strict_init_order)               \143        StopInitOrderChecking();                    \144      CheckNoDeepBind(filename, flag);              \145      REAL(dlopen)(filename, flag);                 \146    })147#  define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()148#  define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)149#  define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()150#  define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!AsanInited())151#  define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \152    if (AsanThread *t = GetCurrentThread()) {          \153      *begin = t->tls_begin();                         \154      *end = t->tls_end();                             \155    } else {                                           \156      *begin = *end = 0;                               \157    }158 159template <class Mmap>160static void* mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,161                              int prot, int flags, int fd, OFF64_T offset) {162  void *res = real_mmap(addr, length, prot, flags, fd, offset);163  if (length && res != (void *)-1) {164    const uptr beg = reinterpret_cast<uptr>(res);165    DCHECK(IsAligned(beg, GetPageSize()));166    SIZE_T rounded_length = RoundUpTo(length, GetPageSize());167    // Only unpoison shadow if it's an ASAN managed address.168    if (AddrIsInMem(beg) && AddrIsInMem(beg + rounded_length - 1))169      PoisonShadow(beg, RoundUpTo(length, GetPageSize()), 0);170  }171  return res;172}173 174template <class Munmap>175static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) {176  // We should not tag if munmap fail, but it's to late to tag after177  // real_munmap, as the pages could be mmaped by another thread.178  const uptr beg = reinterpret_cast<uptr>(addr);179  if (length && IsAligned(beg, GetPageSize())) {180    SIZE_T rounded_length = RoundUpTo(length, GetPageSize());181    // Protect from unmapping the shadow.182    if (AddrIsInMem(beg) && AddrIsInMem(beg + rounded_length - 1))183      PoisonShadow(beg, rounded_length, 0);184  }185  return real_munmap(addr, length);186}187 188#  define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags,   \189                                     fd, offset)                               \190  do {                                                                         \191    (void)(ctx);                                                               \192    return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off);       \193  } while (false)194 195#  define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length)                    \196  do {                                                                         \197    (void)(ctx);                                                               \198    return munmap_interceptor(REAL(munmap), addr, sz);                         \199  } while (false)200 201#if CAN_SANITIZE_LEAKS202#define COMMON_INTERCEPTOR_STRERROR()                       \203  __lsan::ScopedInterceptorDisabler disabler204#endif205 206#  define SIGNAL_INTERCEPTOR_ENTER() \207    do {                             \208      AsanInitFromRtl();             \209    } while (false)210 211#  include "sanitizer_common/sanitizer_common_interceptors.inc"212#  include "sanitizer_common/sanitizer_signal_interceptors.inc"213 214// Syscall interceptors don't have contexts, we don't support suppressions215// for them.216#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s)217#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s)218#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \219  do {                                       \220    (void)(p);                               \221    (void)(s);                               \222  } while (false)223#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \224  do {                                        \225    (void)(p);                                \226    (void)(s);                                \227  } while (false)228#include "sanitizer_common/sanitizer_common_syscalls.inc"229#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"230 231#if ASAN_INTERCEPT_PTHREAD_CREATE232static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {233  AsanThread *t = (AsanThread *)arg;234  SetCurrentThread(t);235  auto self = GetThreadSelf();236  auto args = asanThreadArgRetval().GetArgs(self);237  t->ThreadStart(GetTid());238 239#    if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \240        SANITIZER_SOLARIS241  __sanitizer_sigset_t sigset;242  t->GetStartData(sigset);243  SetSigProcMask(&sigset, nullptr);244#    endif245 246  thread_return_t retval = (*args.routine)(args.arg_retval);247  asanThreadArgRetval().Finish(self, retval);248  return retval;249}250 251INTERCEPTOR(int, pthread_create, void *thread, void *attr,252            void *(*start_routine)(void *), void *arg) {253  EnsureMainThreadIDIsCorrect();254  // Strict init-order checking is thread-hostile.255  if (flags()->strict_init_order)256    StopInitOrderChecking();257  GET_STACK_TRACE_THREAD;258  bool detached = [attr]() {259    int d = 0;260    return attr && !REAL(pthread_attr_getdetachstate)(attr, &d) &&261           IsStateDetached(d);262  }();263 264  u32 current_tid = GetCurrentTidOrInvalid();265 266  __sanitizer_sigset_t sigset = {};267#    if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \268        SANITIZER_SOLARIS269  ScopedBlockSignals block(&sigset);270#    endif271 272  AsanThread *t = AsanThread::Create(sigset, current_tid, &stack, detached);273 274  int result;275  {276    // Ignore all allocations made by pthread_create: thread stack/TLS may be277    // stored by pthread for future reuse even after thread destruction, and278    // the linked list it's stored in doesn't even hold valid pointers to the279    // objects, the latter are calculated by obscure pointer arithmetic.280#    if CAN_SANITIZE_LEAKS281    __lsan::ScopedInterceptorDisabler disabler;282#    endif283    asanThreadArgRetval().Create(detached, {start_routine, arg}, [&]() -> uptr {284      result = REAL(pthread_create)(thread, attr, asan_thread_start, t);285      return result ? 0 : *(uptr *)(thread);286    });287  }288  if (result != 0) {289    // If the thread didn't start delete the AsanThread to avoid leaking it.290    // Note AsanThreadContexts never get destroyed so the AsanThreadContext291    // that was just created for the AsanThread is wasted.292    t->Destroy();293  }294  return result;295}296 297INTERCEPTOR(int, pthread_join, void *thread, void **retval) {298  int result;299  asanThreadArgRetval().Join((uptr)thread, [&]() {300    result = REAL(pthread_join)(thread, retval);301    return !result;302  });303  return result;304}305 306INTERCEPTOR(int, pthread_detach, void *thread) {307  int result;308  asanThreadArgRetval().Detach((uptr)thread, [&]() {309    result = REAL(pthread_detach)(thread);310    return !result;311  });312  return result;313}314 315INTERCEPTOR(void, pthread_exit, void *retval) {316  asanThreadArgRetval().Finish(GetThreadSelf(), retval);317  REAL(pthread_exit)(retval);318}319 320#    if ASAN_INTERCEPT_TRYJOIN321INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) {322  int result;323  asanThreadArgRetval().Join((uptr)thread, [&]() {324    result = REAL(pthread_tryjoin_np)(thread, ret);325    return !result;326  });327  return result;328}329#    endif330 331#    if ASAN_INTERCEPT_TIMEDJOIN332INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,333            const struct timespec *abstime) {334  int result;335  asanThreadArgRetval().Join((uptr)thread, [&]() {336    result = REAL(pthread_timedjoin_np)(thread, ret, abstime);337    return !result;338  });339  return result;340}341#    endif342 343DEFINE_INTERNAL_PTHREAD_FUNCTIONS344#endif  // ASAN_INTERCEPT_PTHREAD_CREATE345 346#if ASAN_INTERCEPT_SWAPCONTEXT347static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {348  // Only clear if we know the stack. This should be true only for contexts349  // created with makecontext().350  if (!ssize)351    return;352  // Align to page size.353  uptr PageSize = GetPageSizeCached();354  uptr bottom = RoundDownTo(stack, PageSize);355  if (!AddrIsInMem(bottom))356    return;357  ssize += stack - bottom;358  ssize = RoundUpTo(ssize, PageSize);359  PoisonShadow(bottom, ssize, 0);360}361 362// Since Solaris 10/SPARC, ucp->uc_stack.ss_sp refers to the stack base address363// as on other targets.  For binary compatibility, the new version uses a364// different external name, so we intercept that.365#    if SANITIZER_SOLARIS && defined(__sparc__)366INTERCEPTOR(void, __makecontext_v2, struct ucontext_t *ucp, void (*func)(),367            int argc, ...) {368#    else369INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc,370            ...) {371#    endif372  va_list ap;373  uptr args[64];374  // We don't know a better way to forward ... into REAL function. We can375  // increase args size if necessary.376  CHECK_LE(argc, ARRAY_SIZE(args));377  internal_memset(args, 0, sizeof(args));378  va_start(ap, argc);379  for (int i = 0; i < argc; ++i) args[i] = va_arg(ap, uptr);380  va_end(ap);381 382#    define ENUMERATE_ARRAY_4(start) \383      args[start], args[start + 1], args[start + 2], args[start + 3]384#    define ENUMERATE_ARRAY_16(start)                         \385      ENUMERATE_ARRAY_4(start), ENUMERATE_ARRAY_4(start + 4), \386          ENUMERATE_ARRAY_4(start + 8), ENUMERATE_ARRAY_4(start + 12)387#    define ENUMERATE_ARRAY_64()                                             \388      ENUMERATE_ARRAY_16(0), ENUMERATE_ARRAY_16(16), ENUMERATE_ARRAY_16(32), \389          ENUMERATE_ARRAY_16(48)390 391#    if SANITIZER_SOLARIS && defined(__sparc__)392  REAL(__makecontext_v2)393#    else394  REAL(makecontext)395#    endif396  ((struct ucontext_t *)ucp, func, argc, ENUMERATE_ARRAY_64());397 398#    undef ENUMERATE_ARRAY_4399#    undef ENUMERATE_ARRAY_16400#    undef ENUMERATE_ARRAY_64401 402  // Sign the stack so we can identify it for unpoisoning.403  SignContextStack(ucp);404}405 406INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,407            struct ucontext_t *ucp) {408  static bool reported_warning = false;409  if (!reported_warning) {410    Report("WARNING: ASan doesn't fully support makecontext/swapcontext "411           "functions and may produce false positives in some cases!\n");412    reported_warning = true;413  }414  // Clear shadow memory for new context (it may share stack415  // with current context).416  uptr stack, ssize;417  ReadContextStack(ucp, &stack, &ssize);418  ClearShadowMemoryForContextStack(stack, ssize);419 420#    if __has_attribute(__indirect_return__) && \421        (defined(__x86_64__) || defined(__i386__))422  int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *)423      __attribute__((__indirect_return__)) = REAL(swapcontext);424  int res = real_swapcontext(oucp, ucp);425#    else426  int res = REAL(swapcontext)(oucp, ucp);427#    endif428  // swapcontext technically does not return, but program may swap context to429  // "oucp" later, that would look as if swapcontext() returned 0.430  // We need to clear shadow for ucp once again, as it may be in arbitrary431  // state.432  ClearShadowMemoryForContextStack(stack, ssize);433  return res;434}435#endif  // ASAN_INTERCEPT_SWAPCONTEXT436 437#if SANITIZER_NETBSD438#define longjmp __longjmp14439#define siglongjmp __siglongjmp14440#endif441 442INTERCEPTOR(void, longjmp, void *env, int val) {443  __asan_handle_no_return();444  REAL(longjmp)(env, val);445}446 447#if ASAN_INTERCEPT__LONGJMP448INTERCEPTOR(void, _longjmp, void *env, int val) {449  __asan_handle_no_return();450  REAL(_longjmp)(env, val);451}452#endif453 454#if ASAN_INTERCEPT___LONGJMP_CHK455INTERCEPTOR(void, __longjmp_chk, void *env, int val) {456  __asan_handle_no_return();457  REAL(__longjmp_chk)(env, val);458}459#endif460 461#if ASAN_INTERCEPT_SIGLONGJMP462INTERCEPTOR(void, siglongjmp, void *env, int val) {463  __asan_handle_no_return();464  REAL(siglongjmp)(env, val);465}466#endif467 468#if ASAN_INTERCEPT___CXA_THROW469INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {470  CHECK(REAL(__cxa_throw));471  __asan_handle_no_return();472  REAL(__cxa_throw)(a, b, c);473}474#endif475 476#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION477INTERCEPTOR(void, __cxa_rethrow_primary_exception, void *a) {478  CHECK(REAL(__cxa_rethrow_primary_exception));479  __asan_handle_no_return();480  REAL(__cxa_rethrow_primary_exception)(a);481}482#endif483 484#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION485INTERCEPTOR(_Unwind_Reason_Code, _Unwind_RaiseException,486            _Unwind_Exception *object) {487  CHECK(REAL(_Unwind_RaiseException));488  __asan_handle_no_return();489  return REAL(_Unwind_RaiseException)(object);490}491#endif492 493#if ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION494INTERCEPTOR(_Unwind_Reason_Code, _Unwind_SjLj_RaiseException,495            _Unwind_Exception *object) {496  CHECK(REAL(_Unwind_SjLj_RaiseException));497  __asan_handle_no_return();498  return REAL(_Unwind_SjLj_RaiseException)(object);499}500#endif501 502#if ASAN_INTERCEPT_INDEX503# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX504INTERCEPTOR(char*, index, const char *string, int c)505  ALIAS(WRAP(strchr));506# else507#  if SANITIZER_APPLE508DECLARE_REAL(char*, index, const char *string, int c)509OVERRIDE_FUNCTION(index, strchr);510#  else511DEFINE_REAL(char*, index, const char *string, int c)512#  endif513# endif514#endif  // ASAN_INTERCEPT_INDEX515 516// For both strcat() and strncat() we need to check the validity of |to|517// argument irrespective of the |from| length.518  INTERCEPTOR(char *, strcat, char *to, const char *from) {519    void *ctx;520    ASAN_INTERCEPTOR_ENTER(ctx, strcat);521    AsanInitFromRtl();522    if (flags()->replace_str) {523      uptr from_length = internal_strlen(from);524      ASAN_READ_RANGE(ctx, from, from_length + 1);525      uptr to_length = internal_strlen(to);526      ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);527      ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);528      // If the copying actually happens, the |from| string should not overlap529      // with the resulting string starting at |to|, which has a length of530      // to_length + from_length + 1.531      if (from_length > 0) {532        CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1, from,533                             from_length + 1);534      }535    }536    return REAL(strcat)(to, from);537  }538 539INTERCEPTOR(char*, strncat, char *to, const char *from, usize size) {540  void *ctx;541  ASAN_INTERCEPTOR_ENTER(ctx, strncat);542  AsanInitFromRtl();543  if (flags()->replace_str) {544    uptr from_length = MaybeRealStrnlen(from, size);545    uptr copy_length = Min<uptr>(size, from_length + 1);546    ASAN_READ_RANGE(ctx, from, copy_length);547    uptr to_length = internal_strlen(to);548    ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);549    ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);550    if (from_length > 0) {551      CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,552                           from, copy_length);553    }554  }555  return REAL(strncat)(to, from, size);556}557 558INTERCEPTOR(char *, strcpy, char *to, const char *from) {559  void *ctx;560  ASAN_INTERCEPTOR_ENTER(ctx, strcpy);561  if constexpr (SANITIZER_APPLE) {562    // strcpy is called from malloc_default_purgeable_zone()563    // in __asan::ReplaceSystemAlloc() on Mac.564    if (UNLIKELY(!AsanInited()))565      return REAL(strcpy)(to, from);566  } else {567    if (!TryAsanInitFromRtl())568      return REAL(strcpy)(to, from);569  }570 571  if (flags()->replace_str) {572    uptr from_size = internal_strlen(from) + 1;573    CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);574    ASAN_READ_RANGE(ctx, from, from_size);575    ASAN_WRITE_RANGE(ctx, to, from_size);576  }577  return REAL(strcpy)(to, from);578}579 580INTERCEPTOR(wchar_t*, wcscpy, wchar_t* to, const wchar_t* from) {581  void* ctx;582  ASAN_INTERCEPTOR_ENTER(ctx, wcscpy);583  if (!TryAsanInitFromRtl())584    return REAL(wcscpy)(to, from);585  if (flags()->replace_str) {586    uptr size = (internal_wcslen(from) + 1) * sizeof(wchar_t);587    CHECK_RANGES_OVERLAP("wcscpy", to, size, from, size);588    ASAN_READ_RANGE(ctx, from, size);589    ASAN_WRITE_RANGE(ctx, to, size);590  }591  return REAL(wcscpy)(to, from);592}593 594// Windows doesn't always define the strdup identifier,595// and when it does it's a macro defined to either _strdup596// or _strdup_dbg, _strdup_dbg ends up calling _strdup, so597// we want to intercept that. push/pop_macro are used to avoid problems598// if this file ends up including <string.h> in the future.599#  if SANITIZER_WINDOWS600#    pragma push_macro("strdup")601#    undef strdup602#    define strdup _strdup603#  endif604 605INTERCEPTOR(char*, strdup, const char *s) {606  void *ctx;607  ASAN_INTERCEPTOR_ENTER(ctx, strdup);608  // Allowing null input is Windows-specific609  if (SANITIZER_WINDOWS && UNLIKELY(!s))610    return nullptr;611  if (UNLIKELY(!TryAsanInitFromRtl()))612    return internal_strdup(s);613  uptr length = internal_strlen(s);614  if (flags()->replace_str) {615    ASAN_READ_RANGE(ctx, s, length + 1);616  }617  GET_STACK_TRACE_MALLOC;618  void *new_mem = asan_malloc(length + 1, &stack);619  if (new_mem) {620    REAL(memcpy)(new_mem, s, length + 1);621  }622  return reinterpret_cast<char*>(new_mem);623}624 625#  if ASAN_INTERCEPT___STRDUP626INTERCEPTOR(char*, __strdup, const char *s) {627  void *ctx;628  ASAN_INTERCEPTOR_ENTER(ctx, strdup);629  if (UNLIKELY(!TryAsanInitFromRtl()))630    return internal_strdup(s);631  uptr length = internal_strlen(s);632  if (flags()->replace_str) {633    ASAN_READ_RANGE(ctx, s, length + 1);634  }635  GET_STACK_TRACE_MALLOC;636  void *new_mem = asan_malloc(length + 1, &stack);637  if (new_mem) {638    REAL(memcpy)(new_mem, s, length + 1);639  }640  return reinterpret_cast<char*>(new_mem);641}642#endif // ASAN_INTERCEPT___STRDUP643 644INTERCEPTOR(char*, strncpy, char *to, const char *from, usize size) {645  void *ctx;646  ASAN_INTERCEPTOR_ENTER(ctx, strncpy);647  AsanInitFromRtl();648  if (flags()->replace_str) {649    uptr from_size = Min<uptr>(size, MaybeRealStrnlen(from, size) + 1);650    CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);651    ASAN_READ_RANGE(ctx, from, from_size);652    ASAN_WRITE_RANGE(ctx, to, size);653  }654  return REAL(strncpy)(to, from, size);655}656 657INTERCEPTOR(wchar_t*, wcsncpy, wchar_t* to, const wchar_t* from, uptr size) {658  void* ctx;659  ASAN_INTERCEPTOR_ENTER(ctx, wcsncpy);660  AsanInitFromRtl();661  if (flags()->replace_str) {662    uptr from_size =663        Min(size, MaybeRealWcsnlen(from, size) + 1) * sizeof(wchar_t);664    CHECK_RANGES_OVERLAP("wcsncpy", to, from_size, from, from_size);665    ASAN_READ_RANGE(ctx, from, from_size);666    ASAN_WRITE_RANGE(ctx, to, size * sizeof(wchar_t));667  }668  return REAL(wcsncpy)(to, from, size);669}670 671template <typename Fn>672static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr,673                                     char **endptr, int base)674    -> decltype(real(nullptr, nullptr, 0)) {675  if (!flags()->replace_str)676    return real(nptr, endptr, base);677  char *real_endptr;678  auto res = real(nptr, &real_endptr, base);679  StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);680  return res;681}682 683#  define INTERCEPTOR_STRTO_BASE(ret_type, func)                             \684    INTERCEPTOR(ret_type, func, const char *nptr, char **endptr, int base) { \685      void *ctx;                                                             \686      ASAN_INTERCEPTOR_ENTER(ctx, func);                                     \687      AsanInitFromRtl();                                                     \688      return StrtolImpl(ctx, REAL(func), nptr, endptr, base);                \689    }690 691INTERCEPTOR_STRTO_BASE(long long, strtoll)692 693#  if SANITIZER_WINDOWS694INTERCEPTOR(long, strtol, const char *nptr, char **endptr, int base) {695  // REAL(strtol) may be ntdll!strtol, which doesn't set errno. Instead,696  // call REAL(strtoll) and do the range check ourselves.697  COMPILER_CHECK(sizeof(long) == sizeof(u32));698 699  void *ctx;700  ASAN_INTERCEPTOR_ENTER(ctx, strtol);701  AsanInitFromRtl();702 703  long long result = StrtolImpl(ctx, REAL(strtoll), nptr, endptr, base);704 705  if (result > INT32_MAX) {706    errno = errno_ERANGE;707    return INT32_MAX;708  }709  if (result < INT32_MIN) {710    errno = errno_ERANGE;711    return INT32_MIN;712  }713  return (long)result;714}715#  else716INTERCEPTOR_STRTO_BASE(long, strtol)717#  endif718 719#  if SANITIZER_GLIBC720INTERCEPTOR_STRTO_BASE(long, __isoc23_strtol)721INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll)722#  endif723 724INTERCEPTOR(int, atoi, const char *nptr) {725  void *ctx;726  ASAN_INTERCEPTOR_ENTER(ctx, atoi);727  if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))728    return REAL(atoi)(nptr);729  AsanInitFromRtl();730  if (!flags()->replace_str) {731    return REAL(atoi)(nptr);732  }733  char *real_endptr;734  // "man atoi" tells that behavior of atoi(nptr) is the same as735  // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the736  // parsed integer can't be stored in *long* type (even if it's737  // different from int). So, we just imitate this behavior.738  int result = REAL(strtol)(nptr, &real_endptr, 10);739  FixRealStrtolEndptr(nptr, &real_endptr);740  ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);741  return result;742}743 744INTERCEPTOR(long, atol, const char *nptr) {745  void *ctx;746  ASAN_INTERCEPTOR_ENTER(ctx, atol);747  if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))748    return REAL(atol)(nptr);749  AsanInitFromRtl();750  if (!flags()->replace_str) {751    return REAL(atol)(nptr);752  }753  char *real_endptr;754  long result = REAL(strtol)(nptr, &real_endptr, 10);755  FixRealStrtolEndptr(nptr, &real_endptr);756  ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);757  return result;758}759 760INTERCEPTOR(long long, atoll, const char *nptr) {761  void *ctx;762  ASAN_INTERCEPTOR_ENTER(ctx, atoll);763  AsanInitFromRtl();764  if (!flags()->replace_str) {765    return REAL(atoll)(nptr);766  }767  char *real_endptr;768  long long result = REAL(strtoll)(nptr, &real_endptr, 10);769  FixRealStrtolEndptr(nptr, &real_endptr);770  ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);771  return result;772}773 774#if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT775static void AtCxaAtexit(void *unused) {776  (void)unused;777  StopInitOrderChecking();778}779#endif780 781#if ASAN_INTERCEPT___CXA_ATEXIT782INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,783            void *dso_handle) {784  if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))785    return REAL(__cxa_atexit)(func, arg, dso_handle);786  AsanInitFromRtl();787#    if CAN_SANITIZE_LEAKS788  __lsan::ScopedInterceptorDisabler disabler;789#endif790  int res = REAL(__cxa_atexit)(func, arg, dso_handle);791  REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);792  return res;793}794#endif  // ASAN_INTERCEPT___CXA_ATEXIT795 796#if ASAN_INTERCEPT_ATEXIT797INTERCEPTOR(int, atexit, void (*func)()) {798  AsanInitFromRtl();799#    if CAN_SANITIZE_LEAKS800  __lsan::ScopedInterceptorDisabler disabler;801#endif802  // Avoid calling real atexit as it is unreachable on at least on Linux.803  int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr);804  REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);805  return res;806}807#endif808 809#if ASAN_INTERCEPT_PTHREAD_ATFORK810extern "C" {811extern int _pthread_atfork(void (*prepare)(), void (*parent)(),812                           void (*child)());813}814 815INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),816            void (*child)()) {817#if CAN_SANITIZE_LEAKS818  __lsan::ScopedInterceptorDisabler disabler;819#endif820  // REAL(pthread_atfork) cannot be called due to symbol indirections at least821  // on NetBSD822  return _pthread_atfork(prepare, parent, child);823}824#endif825 826#if ASAN_INTERCEPT_VFORK827DEFINE_REAL(int, vfork,)828DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,)829#endif830 831// ---------------------- InitializeAsanInterceptors ---------------- {{{1832namespace __asan {833void InitializeAsanInterceptors() {834  static bool was_called_once;835  CHECK(!was_called_once);836  was_called_once = true;837  InitializePlatformInterceptors();838  InitializeCommonInterceptors();839  InitializeSignalInterceptors();840 841  // Intercept str* functions.842  ASAN_INTERCEPT_FUNC(strcat);843  ASAN_INTERCEPT_FUNC(strcpy);844  ASAN_INTERCEPT_FUNC(strncat);845  ASAN_INTERCEPT_FUNC(strncpy);846  ASAN_INTERCEPT_FUNC(strdup);847 848  // Intercept wcs* functions.849  ASAN_INTERCEPT_FUNC(wcscpy);850  ASAN_INTERCEPT_FUNC(wcsncpy);851 852#  if ASAN_INTERCEPT___STRDUP853  ASAN_INTERCEPT_FUNC(__strdup);854#endif855#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX856  ASAN_INTERCEPT_FUNC(index);857#endif858 859  ASAN_INTERCEPT_FUNC(atoi);860  ASAN_INTERCEPT_FUNC(atol);861  ASAN_INTERCEPT_FUNC(atoll);862  ASAN_INTERCEPT_FUNC(strtol);863  ASAN_INTERCEPT_FUNC(strtoll);864#  if SANITIZER_GLIBC865  ASAN_INTERCEPT_FUNC(__isoc23_strtol);866  ASAN_INTERCEPT_FUNC(__isoc23_strtoll);867#  endif868 869  // Intercept jump-related functions.870  ASAN_INTERCEPT_FUNC(longjmp);871 872#  if ASAN_INTERCEPT_SWAPCONTEXT873  ASAN_INTERCEPT_FUNC(swapcontext);874  // See the makecontext interceptor above for an explanation.875#    if SANITIZER_SOLARIS && defined(__sparc__)876  ASAN_INTERCEPT_FUNC(__makecontext_v2);877#    else878  ASAN_INTERCEPT_FUNC(makecontext);879#    endif880#  endif881#  if ASAN_INTERCEPT__LONGJMP882  ASAN_INTERCEPT_FUNC(_longjmp);883#endif884#if ASAN_INTERCEPT___LONGJMP_CHK885  ASAN_INTERCEPT_FUNC(__longjmp_chk);886#endif887#if ASAN_INTERCEPT_SIGLONGJMP888  ASAN_INTERCEPT_FUNC(siglongjmp);889#endif890 891  // Intercept exception handling functions.892#if ASAN_INTERCEPT___CXA_THROW893  ASAN_INTERCEPT_FUNC(__cxa_throw);894#endif895#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION896  ASAN_INTERCEPT_FUNC(__cxa_rethrow_primary_exception);897#endif898  // Indirectly intercept std::rethrow_exception.899#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION900  ASAN_INTERCEPT_FUNC(_Unwind_RaiseException);901#endif902  // Indirectly intercept std::rethrow_exception.903#if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION904  ASAN_INTERCEPT_FUNC(_Unwind_SjLj_RaiseException);905#endif906 907  // Intercept threading-related functions908#if ASAN_INTERCEPT_PTHREAD_CREATE909// TODO: this should probably have an unversioned fallback for newer arches?910#if defined(ASAN_PTHREAD_CREATE_VERSION)911  ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION);912#else913  ASAN_INTERCEPT_FUNC(pthread_create);914#endif915  ASAN_INTERCEPT_FUNC(pthread_join);916  ASAN_INTERCEPT_FUNC(pthread_detach);917  ASAN_INTERCEPT_FUNC(pthread_exit);918#  endif919 920#  if ASAN_INTERCEPT_TIMEDJOIN921  ASAN_INTERCEPT_FUNC(pthread_timedjoin_np);922#endif923 924#if ASAN_INTERCEPT_TRYJOIN925  ASAN_INTERCEPT_FUNC(pthread_tryjoin_np);926#endif927 928  // Intercept atexit function.929#if ASAN_INTERCEPT___CXA_ATEXIT930  ASAN_INTERCEPT_FUNC(__cxa_atexit);931#endif932 933#if ASAN_INTERCEPT_ATEXIT934  ASAN_INTERCEPT_FUNC(atexit);935#endif936 937#if ASAN_INTERCEPT_PTHREAD_ATFORK938  ASAN_INTERCEPT_FUNC(pthread_atfork);939#endif940 941#if ASAN_INTERCEPT_VFORK942  ASAN_INTERCEPT_FUNC(vfork);943#endif944 945  VReport(1, "AddressSanitizer: libc interceptors initialized\n");946}947 948#  if SANITIZER_WINDOWS949#    pragma pop_macro("strdup")950#  endif951 952} // namespace __asan953 954#endif  // !SANITIZER_FUCHSIA955