Path: blob/main/contrib/llvm-project/compiler-rt/lib/asan/asan_interceptors.cpp
35233 views
//===-- asan_interceptors.cpp ---------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of AddressSanitizer, an address sanity checker.9//10// Intercept various libc functions.11//===----------------------------------------------------------------------===//1213#include "asan_interceptors.h"1415#include "asan_allocator.h"16#include "asan_internal.h"17#include "asan_mapping.h"18#include "asan_poisoning.h"19#include "asan_report.h"20#include "asan_stack.h"21#include "asan_stats.h"22#include "asan_suppressions.h"23#include "asan_thread.h"24#include "lsan/lsan_common.h"25#include "sanitizer_common/sanitizer_errno.h"26#include "sanitizer_common/sanitizer_internal_defs.h"27#include "sanitizer_common/sanitizer_libc.h"2829// There is no general interception at all on Fuchsia.30// Only the functions in asan_interceptors_memintrinsics.cpp are31// really defined to replace libc functions.32#if !SANITIZER_FUCHSIA3334# if SANITIZER_POSIX35# include "sanitizer_common/sanitizer_posix.h"36# endif3738# if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION || \39ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION40# include <unwind.h>41# endif4243# if defined(__i386) && SANITIZER_LINUX44# define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1"45# elif defined(__mips__) && SANITIZER_LINUX46# define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2"47# endif4849namespace __asan {5051#define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \52ASAN_READ_RANGE((ctx), (s), \53common_flags()->strict_string_checks ? (len) + 1 : (n))5455# define ASAN_READ_STRING(ctx, s, n) \56ASAN_READ_STRING_OF_LEN((ctx), (s), internal_strlen(s), (n))5758static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {59#if SANITIZER_INTERCEPT_STRNLEN60if (REAL(strnlen)) {61return REAL(strnlen)(s, maxlen);62}63#endif64return internal_strnlen(s, maxlen);65}6667void SetThreadName(const char *name) {68AsanThread *t = GetCurrentThread();69if (t)70asanThreadRegistry().SetThreadName(t->tid(), name);71}7273int OnExit() {74if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks &&75__lsan::HasReportedLeaks()) {76return common_flags()->exitcode;77}78// FIXME: ask frontend whether we need to return failure.79return 0;80}8182} // namespace __asan8384// ---------------------- Wrappers ---------------- {{{185using namespace __asan;8687DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)88DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)8990#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \91ASAN_INTERCEPT_FUNC_VER(name, ver)92#define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \93ASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver)94#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \95ASAN_WRITE_RANGE(ctx, ptr, size)96#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \97ASAN_READ_RANGE(ctx, ptr, size)98# define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \99ASAN_INTERCEPTOR_ENTER(ctx, func); \100do { \101if constexpr (SANITIZER_APPLE) { \102if (UNLIKELY(!AsanInited())) \103return REAL(func)(__VA_ARGS__); \104} else { \105if (!TryAsanInitFromRtl()) \106return REAL(func)(__VA_ARGS__); \107} \108} while (false)109#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \110do { \111} while (false)112#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \113do { \114} while (false)115#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \116do { \117} while (false)118#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \119do { \120} while (false)121#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)122// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name)123// But asan does not remember UserId's for threads (pthread_t);124// and remembers all ever existed threads, so the linear search by UserId125// can be slow.126#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \127do { \128} while (false)129#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)130// Strict init-order checking is dlopen-hostile:131// https://github.com/google/sanitizers/issues/178132# define COMMON_INTERCEPTOR_DLOPEN(filename, flag) \133({ \134if (flags()->strict_init_order) \135StopInitOrderChecking(); \136CheckNoDeepBind(filename, flag); \137REAL(dlopen)(filename, flag); \138})139# define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()140# define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)141# define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()142# define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!AsanInited())143# define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \144if (AsanThread *t = GetCurrentThread()) { \145*begin = t->tls_begin(); \146*end = t->tls_end(); \147} else { \148*begin = *end = 0; \149}150151template <class Mmap>152static void* mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,153int prot, int flags, int fd, OFF64_T offset) {154void *res = real_mmap(addr, length, prot, flags, fd, offset);155if (length && res != (void *)-1) {156const uptr beg = reinterpret_cast<uptr>(res);157DCHECK(IsAligned(beg, GetPageSize()));158SIZE_T rounded_length = RoundUpTo(length, GetPageSize());159// Only unpoison shadow if it's an ASAN managed address.160if (AddrIsInMem(beg) && AddrIsInMem(beg + rounded_length - 1))161PoisonShadow(beg, RoundUpTo(length, GetPageSize()), 0);162}163return res;164}165166template <class Munmap>167static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) {168// We should not tag if munmap fail, but it's to late to tag after169// real_munmap, as the pages could be mmaped by another thread.170const uptr beg = reinterpret_cast<uptr>(addr);171if (length && IsAligned(beg, GetPageSize())) {172SIZE_T rounded_length = RoundUpTo(length, GetPageSize());173// Protect from unmapping the shadow.174if (AddrIsInMem(beg) && AddrIsInMem(beg + rounded_length - 1))175PoisonShadow(beg, rounded_length, 0);176}177return real_munmap(addr, length);178}179180# define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, \181fd, offset) \182do { \183(void)(ctx); \184return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off); \185} while (false)186187# define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length) \188do { \189(void)(ctx); \190return munmap_interceptor(REAL(munmap), addr, sz); \191} while (false)192193#if CAN_SANITIZE_LEAKS194#define COMMON_INTERCEPTOR_STRERROR() \195__lsan::ScopedInterceptorDisabler disabler196#endif197198# define SIGNAL_INTERCEPTOR_ENTER() \199do { \200AsanInitFromRtl(); \201} while (false)202203# include "sanitizer_common/sanitizer_common_interceptors.inc"204# include "sanitizer_common/sanitizer_signal_interceptors.inc"205206// Syscall interceptors don't have contexts, we don't support suppressions207// for them.208#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s)209#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s)210#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \211do { \212(void)(p); \213(void)(s); \214} while (false)215#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \216do { \217(void)(p); \218(void)(s); \219} while (false)220#include "sanitizer_common/sanitizer_common_syscalls.inc"221#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"222223#if ASAN_INTERCEPT_PTHREAD_CREATE224static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {225AsanThread *t = (AsanThread *)arg;226SetCurrentThread(t);227auto self = GetThreadSelf();228auto args = asanThreadArgRetval().GetArgs(self);229t->ThreadStart(GetTid());230231# if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \232SANITIZER_SOLARIS233__sanitizer_sigset_t sigset;234t->GetStartData(sigset);235SetSigProcMask(&sigset, nullptr);236# endif237238thread_return_t retval = (*args.routine)(args.arg_retval);239asanThreadArgRetval().Finish(self, retval);240return retval;241}242243INTERCEPTOR(int, pthread_create, void *thread, void *attr,244void *(*start_routine)(void *), void *arg) {245EnsureMainThreadIDIsCorrect();246// Strict init-order checking is thread-hostile.247if (flags()->strict_init_order)248StopInitOrderChecking();249GET_STACK_TRACE_THREAD;250bool detached = [attr]() {251int d = 0;252return attr && !REAL(pthread_attr_getdetachstate)(attr, &d) &&253IsStateDetached(d);254}();255256u32 current_tid = GetCurrentTidOrInvalid();257258__sanitizer_sigset_t sigset = {};259# if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \260SANITIZER_SOLARIS261ScopedBlockSignals block(&sigset);262# endif263264AsanThread *t = AsanThread::Create(sigset, current_tid, &stack, detached);265266int result;267{268// Ignore all allocations made by pthread_create: thread stack/TLS may be269// stored by pthread for future reuse even after thread destruction, and270// the linked list it's stored in doesn't even hold valid pointers to the271// objects, the latter are calculated by obscure pointer arithmetic.272# if CAN_SANITIZE_LEAKS273__lsan::ScopedInterceptorDisabler disabler;274# endif275asanThreadArgRetval().Create(detached, {start_routine, arg}, [&]() -> uptr {276result = REAL(pthread_create)(thread, attr, asan_thread_start, t);277return result ? 0 : *(uptr *)(thread);278});279}280if (result != 0) {281// If the thread didn't start delete the AsanThread to avoid leaking it.282// Note AsanThreadContexts never get destroyed so the AsanThreadContext283// that was just created for the AsanThread is wasted.284t->Destroy();285}286return result;287}288289INTERCEPTOR(int, pthread_join, void *thread, void **retval) {290int result;291asanThreadArgRetval().Join((uptr)thread, [&]() {292result = REAL(pthread_join)(thread, retval);293return !result;294});295return result;296}297298INTERCEPTOR(int, pthread_detach, void *thread) {299int result;300asanThreadArgRetval().Detach((uptr)thread, [&]() {301result = REAL(pthread_detach)(thread);302return !result;303});304return result;305}306307INTERCEPTOR(void, pthread_exit, void *retval) {308asanThreadArgRetval().Finish(GetThreadSelf(), retval);309REAL(pthread_exit)(retval);310}311312# if ASAN_INTERCEPT_TRYJOIN313INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) {314int result;315asanThreadArgRetval().Join((uptr)thread, [&]() {316result = REAL(pthread_tryjoin_np)(thread, ret);317return !result;318});319return result;320}321# endif322323# if ASAN_INTERCEPT_TIMEDJOIN324INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,325const struct timespec *abstime) {326int result;327asanThreadArgRetval().Join((uptr)thread, [&]() {328result = REAL(pthread_timedjoin_np)(thread, ret, abstime);329return !result;330});331return result;332}333# endif334335DEFINE_INTERNAL_PTHREAD_FUNCTIONS336#endif // ASAN_INTERCEPT_PTHREAD_CREATE337338#if ASAN_INTERCEPT_SWAPCONTEXT339static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {340// Only clear if we know the stack. This should be true only for contexts341// created with makecontext().342if (!ssize)343return;344// Align to page size.345uptr PageSize = GetPageSizeCached();346uptr bottom = RoundDownTo(stack, PageSize);347if (!AddrIsInMem(bottom))348return;349ssize += stack - bottom;350ssize = RoundUpTo(ssize, PageSize);351PoisonShadow(bottom, ssize, 0);352}353354// Since Solaris 10/SPARC, ucp->uc_stack.ss_sp refers to the stack base address355// as on other targets. For binary compatibility, the new version uses a356// different external name, so we intercept that.357# if SANITIZER_SOLARIS && defined(__sparc__)358INTERCEPTOR(void, __makecontext_v2, struct ucontext_t *ucp, void (*func)(),359int argc, ...) {360# else361INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc,362...) {363# endif364va_list ap;365uptr args[64];366// We don't know a better way to forward ... into REAL function. We can367// increase args size if neccecary.368CHECK_LE(argc, ARRAY_SIZE(args));369internal_memset(args, 0, sizeof(args));370va_start(ap, argc);371for (int i = 0; i < argc; ++i) args[i] = va_arg(ap, uptr);372va_end(ap);373374# define ENUMERATE_ARRAY_4(start) \375args[start], args[start + 1], args[start + 2], args[start + 3]376# define ENUMERATE_ARRAY_16(start) \377ENUMERATE_ARRAY_4(start), ENUMERATE_ARRAY_4(start + 4), \378ENUMERATE_ARRAY_4(start + 8), ENUMERATE_ARRAY_4(start + 12)379# define ENUMERATE_ARRAY_64() \380ENUMERATE_ARRAY_16(0), ENUMERATE_ARRAY_16(16), ENUMERATE_ARRAY_16(32), \381ENUMERATE_ARRAY_16(48)382383# if SANITIZER_SOLARIS && defined(__sparc__)384REAL(__makecontext_v2)385# else386REAL(makecontext)387# endif388((struct ucontext_t *)ucp, func, argc, ENUMERATE_ARRAY_64());389390# undef ENUMERATE_ARRAY_4391# undef ENUMERATE_ARRAY_16392# undef ENUMERATE_ARRAY_64393394// Sign the stack so we can identify it for unpoisoning.395SignContextStack(ucp);396}397398INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,399struct ucontext_t *ucp) {400static bool reported_warning = false;401if (!reported_warning) {402Report("WARNING: ASan doesn't fully support makecontext/swapcontext "403"functions and may produce false positives in some cases!\n");404reported_warning = true;405}406// Clear shadow memory for new context (it may share stack407// with current context).408uptr stack, ssize;409ReadContextStack(ucp, &stack, &ssize);410ClearShadowMemoryForContextStack(stack, ssize);411412# if __has_attribute(__indirect_return__) && \413(defined(__x86_64__) || defined(__i386__))414int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *)415__attribute__((__indirect_return__)) = REAL(swapcontext);416int res = real_swapcontext(oucp, ucp);417# else418int res = REAL(swapcontext)(oucp, ucp);419# endif420// swapcontext technically does not return, but program may swap context to421// "oucp" later, that would look as if swapcontext() returned 0.422// We need to clear shadow for ucp once again, as it may be in arbitrary423// state.424ClearShadowMemoryForContextStack(stack, ssize);425return res;426}427#endif // ASAN_INTERCEPT_SWAPCONTEXT428429#if SANITIZER_NETBSD430#define longjmp __longjmp14431#define siglongjmp __siglongjmp14432#endif433434INTERCEPTOR(void, longjmp, void *env, int val) {435__asan_handle_no_return();436REAL(longjmp)(env, val);437}438439#if ASAN_INTERCEPT__LONGJMP440INTERCEPTOR(void, _longjmp, void *env, int val) {441__asan_handle_no_return();442REAL(_longjmp)(env, val);443}444#endif445446#if ASAN_INTERCEPT___LONGJMP_CHK447INTERCEPTOR(void, __longjmp_chk, void *env, int val) {448__asan_handle_no_return();449REAL(__longjmp_chk)(env, val);450}451#endif452453#if ASAN_INTERCEPT_SIGLONGJMP454INTERCEPTOR(void, siglongjmp, void *env, int val) {455__asan_handle_no_return();456REAL(siglongjmp)(env, val);457}458#endif459460#if ASAN_INTERCEPT___CXA_THROW461INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {462CHECK(REAL(__cxa_throw));463__asan_handle_no_return();464REAL(__cxa_throw)(a, b, c);465}466#endif467468#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION469INTERCEPTOR(void, __cxa_rethrow_primary_exception, void *a) {470CHECK(REAL(__cxa_rethrow_primary_exception));471__asan_handle_no_return();472REAL(__cxa_rethrow_primary_exception)(a);473}474#endif475476#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION477INTERCEPTOR(_Unwind_Reason_Code, _Unwind_RaiseException,478_Unwind_Exception *object) {479CHECK(REAL(_Unwind_RaiseException));480__asan_handle_no_return();481return REAL(_Unwind_RaiseException)(object);482}483#endif484485#if ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION486INTERCEPTOR(_Unwind_Reason_Code, _Unwind_SjLj_RaiseException,487_Unwind_Exception *object) {488CHECK(REAL(_Unwind_SjLj_RaiseException));489__asan_handle_no_return();490return REAL(_Unwind_SjLj_RaiseException)(object);491}492#endif493494#if ASAN_INTERCEPT_INDEX495# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX496INTERCEPTOR(char*, index, const char *string, int c)497ALIAS(WRAP(strchr));498# else499# if SANITIZER_APPLE500DECLARE_REAL(char*, index, const char *string, int c)501OVERRIDE_FUNCTION(index, strchr);502# else503DEFINE_REAL(char*, index, const char *string, int c)504# endif505# endif506#endif // ASAN_INTERCEPT_INDEX507508// For both strcat() and strncat() we need to check the validity of |to|509// argument irrespective of the |from| length.510INTERCEPTOR(char *, strcat, char *to, const char *from) {511void *ctx;512ASAN_INTERCEPTOR_ENTER(ctx, strcat);513AsanInitFromRtl();514if (flags()->replace_str) {515uptr from_length = internal_strlen(from);516ASAN_READ_RANGE(ctx, from, from_length + 1);517uptr to_length = internal_strlen(to);518ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);519ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);520// If the copying actually happens, the |from| string should not overlap521// with the resulting string starting at |to|, which has a length of522// to_length + from_length + 1.523if (from_length > 0) {524CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1, from,525from_length + 1);526}527}528return REAL(strcat)(to, from);529}530531INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {532void *ctx;533ASAN_INTERCEPTOR_ENTER(ctx, strncat);534AsanInitFromRtl();535if (flags()->replace_str) {536uptr from_length = MaybeRealStrnlen(from, size);537uptr copy_length = Min(size, from_length + 1);538ASAN_READ_RANGE(ctx, from, copy_length);539uptr to_length = internal_strlen(to);540ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);541ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);542if (from_length > 0) {543CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,544from, copy_length);545}546}547return REAL(strncat)(to, from, size);548}549550INTERCEPTOR(char *, strcpy, char *to, const char *from) {551void *ctx;552ASAN_INTERCEPTOR_ENTER(ctx, strcpy);553if constexpr (SANITIZER_APPLE) {554// strcpy is called from malloc_default_purgeable_zone()555// in __asan::ReplaceSystemAlloc() on Mac.556if (UNLIKELY(!AsanInited()))557return REAL(strcpy)(to, from);558} else {559if (!TryAsanInitFromRtl())560return REAL(strcpy)(to, from);561}562563if (flags()->replace_str) {564uptr from_size = internal_strlen(from) + 1;565CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);566ASAN_READ_RANGE(ctx, from, from_size);567ASAN_WRITE_RANGE(ctx, to, from_size);568}569return REAL(strcpy)(to, from);570}571572// Windows doesn't always define the strdup identifier,573// and when it does it's a macro defined to either _strdup574// or _strdup_dbg, _strdup_dbg ends up calling _strdup, so575// we want to intercept that. push/pop_macro are used to avoid problems576// if this file ends up including <string.h> in the future.577# if SANITIZER_WINDOWS578# pragma push_macro("strdup")579# undef strdup580# define strdup _strdup581# endif582583INTERCEPTOR(char*, strdup, const char *s) {584void *ctx;585ASAN_INTERCEPTOR_ENTER(ctx, strdup);586if (UNLIKELY(!TryAsanInitFromRtl()))587return internal_strdup(s);588uptr length = internal_strlen(s);589if (flags()->replace_str) {590ASAN_READ_RANGE(ctx, s, length + 1);591}592GET_STACK_TRACE_MALLOC;593void *new_mem = asan_malloc(length + 1, &stack);594if (new_mem) {595REAL(memcpy)(new_mem, s, length + 1);596}597return reinterpret_cast<char*>(new_mem);598}599600# if ASAN_INTERCEPT___STRDUP601INTERCEPTOR(char*, __strdup, const char *s) {602void *ctx;603ASAN_INTERCEPTOR_ENTER(ctx, strdup);604if (UNLIKELY(!TryAsanInitFromRtl()))605return internal_strdup(s);606uptr length = internal_strlen(s);607if (flags()->replace_str) {608ASAN_READ_RANGE(ctx, s, length + 1);609}610GET_STACK_TRACE_MALLOC;611void *new_mem = asan_malloc(length + 1, &stack);612if (new_mem) {613REAL(memcpy)(new_mem, s, length + 1);614}615return reinterpret_cast<char*>(new_mem);616}617#endif // ASAN_INTERCEPT___STRDUP618619INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {620void *ctx;621ASAN_INTERCEPTOR_ENTER(ctx, strncpy);622AsanInitFromRtl();623if (flags()->replace_str) {624uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1);625CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);626ASAN_READ_RANGE(ctx, from, from_size);627ASAN_WRITE_RANGE(ctx, to, size);628}629return REAL(strncpy)(to, from, size);630}631632template <typename Fn>633static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr,634char **endptr, int base)635-> decltype(real(nullptr, nullptr, 0)) {636if (!flags()->replace_str)637return real(nptr, endptr, base);638char *real_endptr;639auto res = real(nptr, &real_endptr, base);640StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);641return res;642}643644# define INTERCEPTOR_STRTO_BASE(ret_type, func) \645INTERCEPTOR(ret_type, func, const char *nptr, char **endptr, int base) { \646void *ctx; \647ASAN_INTERCEPTOR_ENTER(ctx, func); \648AsanInitFromRtl(); \649return StrtolImpl(ctx, REAL(func), nptr, endptr, base); \650}651652INTERCEPTOR_STRTO_BASE(long, strtol)653INTERCEPTOR_STRTO_BASE(long long, strtoll)654655# if SANITIZER_GLIBC656INTERCEPTOR_STRTO_BASE(long, __isoc23_strtol)657INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll)658# endif659660INTERCEPTOR(int, atoi, const char *nptr) {661void *ctx;662ASAN_INTERCEPTOR_ENTER(ctx, atoi);663if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))664return REAL(atoi)(nptr);665AsanInitFromRtl();666if (!flags()->replace_str) {667return REAL(atoi)(nptr);668}669char *real_endptr;670// "man atoi" tells that behavior of atoi(nptr) is the same as671// strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the672// parsed integer can't be stored in *long* type (even if it's673// different from int). So, we just imitate this behavior.674int result = REAL(strtol)(nptr, &real_endptr, 10);675FixRealStrtolEndptr(nptr, &real_endptr);676ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);677return result;678}679680INTERCEPTOR(long, atol, const char *nptr) {681void *ctx;682ASAN_INTERCEPTOR_ENTER(ctx, atol);683if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))684return REAL(atol)(nptr);685AsanInitFromRtl();686if (!flags()->replace_str) {687return REAL(atol)(nptr);688}689char *real_endptr;690long result = REAL(strtol)(nptr, &real_endptr, 10);691FixRealStrtolEndptr(nptr, &real_endptr);692ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);693return result;694}695696INTERCEPTOR(long long, atoll, const char *nptr) {697void *ctx;698ASAN_INTERCEPTOR_ENTER(ctx, atoll);699AsanInitFromRtl();700if (!flags()->replace_str) {701return REAL(atoll)(nptr);702}703char *real_endptr;704long long result = REAL(strtoll)(nptr, &real_endptr, 10);705FixRealStrtolEndptr(nptr, &real_endptr);706ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);707return result;708}709710#if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT711static void AtCxaAtexit(void *unused) {712(void)unused;713StopInitOrderChecking();714}715#endif716717#if ASAN_INTERCEPT___CXA_ATEXIT718INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,719void *dso_handle) {720if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))721return REAL(__cxa_atexit)(func, arg, dso_handle);722AsanInitFromRtl();723# if CAN_SANITIZE_LEAKS724__lsan::ScopedInterceptorDisabler disabler;725#endif726int res = REAL(__cxa_atexit)(func, arg, dso_handle);727REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);728return res;729}730#endif // ASAN_INTERCEPT___CXA_ATEXIT731732#if ASAN_INTERCEPT_ATEXIT733INTERCEPTOR(int, atexit, void (*func)()) {734AsanInitFromRtl();735# if CAN_SANITIZE_LEAKS736__lsan::ScopedInterceptorDisabler disabler;737#endif738// Avoid calling real atexit as it is unreachable on at least on Linux.739int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr);740REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);741return res;742}743#endif744745#if ASAN_INTERCEPT_PTHREAD_ATFORK746extern "C" {747extern int _pthread_atfork(void (*prepare)(), void (*parent)(),748void (*child)());749}750751INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),752void (*child)()) {753#if CAN_SANITIZE_LEAKS754__lsan::ScopedInterceptorDisabler disabler;755#endif756// REAL(pthread_atfork) cannot be called due to symbol indirections at least757// on NetBSD758return _pthread_atfork(prepare, parent, child);759}760#endif761762#if ASAN_INTERCEPT_VFORK763DEFINE_REAL(int, vfork,)764DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,)765#endif766767// ---------------------- InitializeAsanInterceptors ---------------- {{{1768namespace __asan {769void InitializeAsanInterceptors() {770static bool was_called_once;771CHECK(!was_called_once);772was_called_once = true;773InitializePlatformInterceptors();774InitializeCommonInterceptors();775InitializeSignalInterceptors();776777// Intercept str* functions.778ASAN_INTERCEPT_FUNC(strcat);779ASAN_INTERCEPT_FUNC(strcpy);780ASAN_INTERCEPT_FUNC(strncat);781ASAN_INTERCEPT_FUNC(strncpy);782ASAN_INTERCEPT_FUNC(strdup);783# if ASAN_INTERCEPT___STRDUP784ASAN_INTERCEPT_FUNC(__strdup);785#endif786#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX787ASAN_INTERCEPT_FUNC(index);788#endif789790ASAN_INTERCEPT_FUNC(atoi);791ASAN_INTERCEPT_FUNC(atol);792ASAN_INTERCEPT_FUNC(atoll);793ASAN_INTERCEPT_FUNC(strtol);794ASAN_INTERCEPT_FUNC(strtoll);795# if SANITIZER_GLIBC796ASAN_INTERCEPT_FUNC(__isoc23_strtol);797ASAN_INTERCEPT_FUNC(__isoc23_strtoll);798# endif799800// Intecept jump-related functions.801ASAN_INTERCEPT_FUNC(longjmp);802803# if ASAN_INTERCEPT_SWAPCONTEXT804ASAN_INTERCEPT_FUNC(swapcontext);805// See the makecontext interceptor above for an explanation.806# if SANITIZER_SOLARIS && defined(__sparc__)807ASAN_INTERCEPT_FUNC(__makecontext_v2);808# else809ASAN_INTERCEPT_FUNC(makecontext);810# endif811# endif812# if ASAN_INTERCEPT__LONGJMP813ASAN_INTERCEPT_FUNC(_longjmp);814#endif815#if ASAN_INTERCEPT___LONGJMP_CHK816ASAN_INTERCEPT_FUNC(__longjmp_chk);817#endif818#if ASAN_INTERCEPT_SIGLONGJMP819ASAN_INTERCEPT_FUNC(siglongjmp);820#endif821822// Intercept exception handling functions.823#if ASAN_INTERCEPT___CXA_THROW824ASAN_INTERCEPT_FUNC(__cxa_throw);825#endif826#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION827ASAN_INTERCEPT_FUNC(__cxa_rethrow_primary_exception);828#endif829// Indirectly intercept std::rethrow_exception.830#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION831ASAN_INTERCEPT_FUNC(_Unwind_RaiseException);832#endif833// Indirectly intercept std::rethrow_exception.834#if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION835ASAN_INTERCEPT_FUNC(_Unwind_SjLj_RaiseException);836#endif837838// Intercept threading-related functions839#if ASAN_INTERCEPT_PTHREAD_CREATE840// TODO: this should probably have an unversioned fallback for newer arches?841#if defined(ASAN_PTHREAD_CREATE_VERSION)842ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION);843#else844ASAN_INTERCEPT_FUNC(pthread_create);845#endif846ASAN_INTERCEPT_FUNC(pthread_join);847ASAN_INTERCEPT_FUNC(pthread_detach);848ASAN_INTERCEPT_FUNC(pthread_exit);849# endif850851# if ASAN_INTERCEPT_TIMEDJOIN852ASAN_INTERCEPT_FUNC(pthread_timedjoin_np);853#endif854855#if ASAN_INTERCEPT_TRYJOIN856ASAN_INTERCEPT_FUNC(pthread_tryjoin_np);857#endif858859// Intercept atexit function.860#if ASAN_INTERCEPT___CXA_ATEXIT861ASAN_INTERCEPT_FUNC(__cxa_atexit);862#endif863864#if ASAN_INTERCEPT_ATEXIT865ASAN_INTERCEPT_FUNC(atexit);866#endif867868#if ASAN_INTERCEPT_PTHREAD_ATFORK869ASAN_INTERCEPT_FUNC(pthread_atfork);870#endif871872#if ASAN_INTERCEPT_VFORK873ASAN_INTERCEPT_FUNC(vfork);874#endif875876VReport(1, "AddressSanitizer: libc interceptors initialized\n");877}878879# if SANITIZER_WINDOWS880# pragma pop_macro("strdup")881# endif882883} // namespace __asan884885#endif // !SANITIZER_FUCHSIA886887888