From 9fd01e5ea58a408b15027de7ce43619882f79655 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Mon, 9 Jan 2012 18:53:15 +0000 Subject: [PATCH] [asan] refactoring: move all interceptors to a single file llvm-svn: 147784 --- compiler-rt/lib/asan/asan_interceptors.cc | 181 ++++++++++++++++++ compiler-rt/lib/asan/asan_interceptors.h | 4 + compiler-rt/lib/asan/asan_internal.h | 3 + compiler-rt/lib/asan/asan_linux.cc | 4 + compiler-rt/lib/asan/asan_mac.cc | 4 + compiler-rt/lib/asan/asan_rtl.cc | 219 +--------------------- 6 files changed, 206 insertions(+), 209 deletions(-) diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc index 53ef91ae857b..5033a7316723 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cc +++ b/compiler-rt/lib/asan/asan_interceptors.cc @@ -19,7 +19,9 @@ #include "asan_mapping.h" #include "asan_stack.h" #include "asan_stats.h" +#include "asan_thread_registry.h" +#include #include #include #include @@ -27,6 +29,29 @@ namespace __asan { +typedef void (*longjmp_f)(void *env, int val); +typedef longjmp_f _longjmp_f; +typedef longjmp_f siglongjmp_f; +typedef void (*__cxa_throw_f)(void *, void *, void *); +typedef int (*pthread_create_f)(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg); +#ifdef __APPLE__ +dispatch_async_f_f real_dispatch_async_f; +dispatch_sync_f_f real_dispatch_sync_f; +dispatch_after_f_f real_dispatch_after_f; +dispatch_barrier_async_f_f real_dispatch_barrier_async_f; +dispatch_group_async_f_f real_dispatch_group_async_f; +pthread_workqueue_additem_np_f real_pthread_workqueue_additem_np; +#endif + +sigaction_f real_sigaction; +signal_f real_signal; +longjmp_f real_longjmp; +_longjmp_f real__longjmp; +siglongjmp_f real_siglongjmp; +__cxa_throw_f real___cxa_throw; +pthread_create_f real_pthread_create; + index_f real_index; memcmp_f real_memcmp; memcpy_f real_memcpy; @@ -156,6 +181,32 @@ void InitializeAsanInterceptors() { INTERCEPT_FUNCTION(strncasecmp); INTERCEPT_FUNCTION(strncmp); INTERCEPT_FUNCTION(strncpy); + + INTERCEPT_FUNCTION(sigaction); + INTERCEPT_FUNCTION(signal); + INTERCEPT_FUNCTION(longjmp); + INTERCEPT_FUNCTION(_longjmp); + INTERCEPT_FUNCTION_IF_EXISTS(__cxa_throw); + INTERCEPT_FUNCTION(pthread_create); + +#ifdef __APPLE__ + INTERCEPT_FUNCTION(dispatch_async_f); + INTERCEPT_FUNCTION(dispatch_sync_f); + INTERCEPT_FUNCTION(dispatch_after_f); + INTERCEPT_FUNCTION(dispatch_barrier_async_f); + INTERCEPT_FUNCTION(dispatch_group_async_f); + // We don't need to intercept pthread_workqueue_additem_np() to support the + // libdispatch API, but it helps us to debug the unsupported functions. Let's + // intercept it only during verbose runs. + if (FLAG_v >= 2) { + INTERCEPT_FUNCTION(pthread_workqueue_additem_np); + } +#else + // On Darwin siglongjmp tailcalls longjmp, so we don't want to intercept it + // there. + INTERCEPT_FUNCTION(siglongjmp); +#endif + #ifndef __APPLE__ INTERCEPT_FUNCTION(strnlen); #endif @@ -169,6 +220,136 @@ void InitializeAsanInterceptors() { // ---------------------- Wrappers ---------------- {{{1 using namespace __asan; // NOLINT +#define OPERATOR_NEW_BODY \ + GET_STACK_TRACE_HERE_FOR_MALLOC;\ + return asan_memalign(0, size, &stack); + +#ifdef ANDROID +void *operator new(size_t size) { OPERATOR_NEW_BODY; } +void *operator new[](size_t size) { OPERATOR_NEW_BODY; } +#else +void *operator new(size_t size) throw(std::bad_alloc) { OPERATOR_NEW_BODY; } +void *operator new[](size_t size) throw(std::bad_alloc) { OPERATOR_NEW_BODY; } +void *operator new(size_t size, std::nothrow_t const&) throw() +{ OPERATOR_NEW_BODY; } +void *operator new[](size_t size, std::nothrow_t const&) throw() +{ OPERATOR_NEW_BODY; } +#endif + +#define OPERATOR_DELETE_BODY \ + GET_STACK_TRACE_HERE_FOR_FREE(ptr);\ + asan_free(ptr, &stack); + +void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY; } +void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY; } +void operator delete(void *ptr, std::nothrow_t const&) throw() +{ OPERATOR_DELETE_BODY; } +void operator delete[](void *ptr, std::nothrow_t const&) throw() +{ OPERATOR_DELETE_BODY;} + +static void *asan_thread_start(void *arg) { + AsanThread *t = (AsanThread*)arg; + asanThreadRegistry().SetCurrent(t); + return t->ThreadStart(); +} + +extern "C" +#ifndef __APPLE__ +__attribute__((visibility("default"))) +#endif +int WRAP(pthread_create)(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg) { + GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false); + AsanThread *curr_thread = asanThreadRegistry().GetCurrent(); + CHECK(curr_thread || asanThreadRegistry().IsCurrentThreadDying()); + int current_tid = asanThreadRegistry().GetCurrentTidOrMinusOne(); + AsanThread *t = AsanThread::Create(current_tid, start_routine, arg); + asanThreadRegistry().RegisterThread(t, current_tid, &stack); + return real_pthread_create(thread, attr, asan_thread_start, t); +} + +extern "C" +void *WRAP(signal)(int signum, void *handler) { + if (!AsanInterceptsSignal(signum)) { + return real_signal(signum, handler); + } + return NULL; +} + +extern "C" +int WRAP(sigaction)(int signum, const struct sigaction *act, + struct sigaction *oldact) { + if (!AsanInterceptsSignal(signum)) { + return real_sigaction(signum, act, oldact); + } + return 0; +} + + +static void UnpoisonStackFromHereToTop() { + int local_stack; + AsanThread *curr_thread = asanThreadRegistry().GetCurrent(); + CHECK(curr_thread); + uintptr_t top = curr_thread->stack_top(); + uintptr_t bottom = ((uintptr_t)&local_stack - kPageSize) & ~(kPageSize-1); + PoisonShadow(bottom, top - bottom, 0); +} + +extern "C" void WRAP(longjmp)(void *env, int val) { + UnpoisonStackFromHereToTop(); + real_longjmp(env, val); +} + +extern "C" void WRAP(_longjmp)(void *env, int val) { + UnpoisonStackFromHereToTop(); + real__longjmp(env, val); +} + +extern "C" void WRAP(siglongjmp)(void *env, int val) { + UnpoisonStackFromHereToTop(); + real_siglongjmp(env, val); +} + +extern "C" void __cxa_throw(void *a, void *b, void *c); + +#if ASAN_HAS_EXCEPTIONS == 1 +extern "C" void WRAP(__cxa_throw)(void *a, void *b, void *c) { + CHECK(&real___cxa_throw); + UnpoisonStackFromHereToTop(); + real___cxa_throw(a, b, c); +} +#endif + +extern "C" { +// intercept mlock and friends. +// Since asan maps 16T of RAM, mlock is completely unfriendly to asan. +// All functions return 0 (success). +static void MlockIsUnsupported() { + static bool printed = 0; + if (printed) return; + printed = true; + Printf("INFO: AddressSanitizer ignores mlock/mlockall/munlock/munlockall\n"); +} +int mlock(const void *addr, size_t len) { + MlockIsUnsupported(); + return 0; +} +int munlock(const void *addr, size_t len) { + MlockIsUnsupported(); + return 0; +} +int mlockall(int flags) { + MlockIsUnsupported(); + return 0; +} +int munlockall(void) { + MlockIsUnsupported(); + return 0; +} +} // extern "C" + + + static inline int CharCmp(unsigned char c1, unsigned char c2) { return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; } diff --git a/compiler-rt/lib/asan/asan_interceptors.h b/compiler-rt/lib/asan/asan_interceptors.h index 07b94208197d..d9bfe8f56f3e 100644 --- a/compiler-rt/lib/asan/asan_interceptors.h +++ b/compiler-rt/lib/asan/asan_interceptors.h @@ -101,6 +101,8 @@ typedef int (*strncasecmp_f)(const char *s1, const char *s2, size_t n); typedef int (*strncmp_f)(const char *s1, const char *s2, size_t size); typedef char* (*strncpy_f)(char *to, const char *from, size_t size); typedef size_t (*strnlen_f)(const char *s, size_t maxlen); +typedef void *(*signal_f)(int signum, void *handler); +typedef int (*sigaction_f)(int signum, const void *act, void *oldact); // __asan::real_X() holds pointer to library implementation of X(). extern index_f real_index; @@ -119,6 +121,8 @@ extern strncasecmp_f real_strncasecmp; extern strncmp_f real_strncmp; extern strncpy_f real_strncpy; extern strnlen_f real_strnlen; +extern signal_f real_signal; +extern sigaction_f real_sigaction; // __asan::internal_X() is the implementation of X() for use in RTL. size_t internal_strlen(const char *s); diff --git a/compiler-rt/lib/asan/asan_internal.h b/compiler-rt/lib/asan/asan_internal.h index 169ed5311009..878f4de8ebcc 100644 --- a/compiler-rt/lib/asan/asan_internal.h +++ b/compiler-rt/lib/asan/asan_internal.h @@ -106,6 +106,8 @@ ssize_t AsanRead(int fd, void *buf, size_t count); ssize_t AsanWrite(int fd, const void *buf, size_t count); int AsanClose(int fd); +bool AsanInterceptsSignal(int signum); + // Opens the file 'file_name" and reads up to 'max_len' bytes. // The resulting buffer is mmaped and stored in '*buff'. // The size of the mmaped region is stored in '*buff_size', @@ -151,6 +153,7 @@ extern bool FLAG_use_fake_stack; extern size_t FLAG_max_malloc_fill_size; extern int FLAG_exitcode; extern bool FLAG_allow_user_poisoning; +extern bool FLAG_handle_segv; extern int asan_inited; // Used to avoid infinite recursion in __asan_init(). diff --git a/compiler-rt/lib/asan/asan_linux.cc b/compiler-rt/lib/asan/asan_linux.cc index 2167efa4a872..70214c53cd0a 100644 --- a/compiler-rt/lib/asan/asan_linux.cc +++ b/compiler-rt/lib/asan/asan_linux.cc @@ -64,6 +64,10 @@ void GetPcSpBp(void *context, uintptr_t *pc, uintptr_t *sp, uintptr_t *bp) { #endif } +bool AsanInterceptsSignal(int signum) { + return signum == SIGSEGV && FLAG_handle_segv; +} + static void *asan_mmap(void *addr, size_t length, int prot, int flags, int fd, uint64_t offset) { # if __WORDSIZE == 64 diff --git a/compiler-rt/lib/asan/asan_mac.cc b/compiler-rt/lib/asan/asan_mac.cc index 6051d83be00a..86bbe7689d72 100644 --- a/compiler-rt/lib/asan/asan_mac.cc +++ b/compiler-rt/lib/asan/asan_mac.cc @@ -56,6 +56,10 @@ void *AsanDoesNotSupportStaticLinkage() { return NULL; } +bool AsanInterceptsSignal(int signum) { + return (signum == SIGSEGV || signum == SIGBUS) && FLAG_handle_segv; +} + static void *asan_mmap(void *addr, size_t length, int prot, int flags, int fd, uint64_t offset) { return mmap(addr, length, prot, flags, fd, offset); diff --git a/compiler-rt/lib/asan/asan_rtl.cc b/compiler-rt/lib/asan/asan_rtl.cc index 8970be8d95b0..09987e2e6a5e 100644 --- a/compiler-rt/lib/asan/asan_rtl.cc +++ b/compiler-rt/lib/asan/asan_rtl.cc @@ -24,19 +24,9 @@ #include "asan_thread.h" #include "asan_thread_registry.h" -#include -#include -#include #include #include -#include -#include -#include -#include #include -#include -#include -// must not include on Linux namespace __asan { @@ -69,33 +59,6 @@ bool FLAG_allow_user_poisoning; int asan_inited; bool asan_init_is_running; -// -------------------------- Interceptors ---------------- {{{1 -typedef int (*sigaction_f)(int signum, const struct sigaction *act, - struct sigaction *oldact); -typedef sig_t (*signal_f)(int signum, sig_t handler); -typedef void (*longjmp_f)(void *env, int val); -typedef longjmp_f _longjmp_f; -typedef longjmp_f siglongjmp_f; -typedef void (*__cxa_throw_f)(void *, void *, void *); -typedef int (*pthread_create_f)(pthread_t *thread, const pthread_attr_t *attr, - void *(*start_routine) (void *), void *arg); -#ifdef __APPLE__ -dispatch_async_f_f real_dispatch_async_f; -dispatch_sync_f_f real_dispatch_sync_f; -dispatch_after_f_f real_dispatch_after_f; -dispatch_barrier_async_f_f real_dispatch_barrier_async_f; -dispatch_group_async_f_f real_dispatch_group_async_f; -pthread_workqueue_additem_np_f real_pthread_workqueue_additem_np; -#endif - -sigaction_f real_sigaction; -signal_f real_signal; -longjmp_f real_longjmp; -_longjmp_f real__longjmp; -siglongjmp_f real_siglongjmp; -__cxa_throw_f real___cxa_throw; -pthread_create_f real_pthread_create; - // -------------------------- Misc ---------------- {{{1 void ShowStatsAndAbort() { __asan_print_accumulated_stats(); @@ -161,11 +124,15 @@ static const char* GetEnvFromProcSelfEnviron(const char* name) { return NULL; // Not found. } -// ---------------------- Thread ------------------------- {{{1 -static void *asan_thread_start(void *arg) { - AsanThread *t= (AsanThread*)arg; - asanThreadRegistry().SetCurrent(t); - return t->ThreadStart(); +static void MaybeInstallSigaction(int signum, + void (*handler)(int, siginfo_t *, void *)) { + if (!AsanInterceptsSignal(signum)) + return; + struct sigaction sigact; + real_memset(&sigact, 0, sizeof(sigact)); + sigact.sa_sigaction = handler; + sigact.sa_flags = SA_SIGINFO; + CHECK(0 == real_sigaction(signum, &sigact, 0)); } // ---------------------- mmap -------------------- {{{1 @@ -359,151 +326,9 @@ void CheckFailed(const char *cond, const char *file, int line) { } // namespace __asan -// -------------------------- Interceptors ------------------- {{{1 +// ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT -#define OPERATOR_NEW_BODY \ - GET_STACK_TRACE_HERE_FOR_MALLOC;\ - return asan_memalign(0, size, &stack); - -#ifdef ANDROID -void *operator new(size_t size) { OPERATOR_NEW_BODY; } -void *operator new[](size_t size) { OPERATOR_NEW_BODY; } -#else -void *operator new(size_t size) throw(std::bad_alloc) { OPERATOR_NEW_BODY; } -void *operator new[](size_t size) throw(std::bad_alloc) { OPERATOR_NEW_BODY; } -void *operator new(size_t size, std::nothrow_t const&) throw() -{ OPERATOR_NEW_BODY; } -void *operator new[](size_t size, std::nothrow_t const&) throw() -{ OPERATOR_NEW_BODY; } -#endif - -#define OPERATOR_DELETE_BODY \ - GET_STACK_TRACE_HERE_FOR_FREE(ptr);\ - asan_free(ptr, &stack); - -void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY; } -void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY; } -void operator delete(void *ptr, std::nothrow_t const&) throw() -{ OPERATOR_DELETE_BODY; } -void operator delete[](void *ptr, std::nothrow_t const&) throw() -{ OPERATOR_DELETE_BODY;} - -extern "C" -#ifndef __APPLE__ -__attribute__((visibility("default"))) -#endif -int WRAP(pthread_create)(pthread_t *thread, const pthread_attr_t *attr, - void *(*start_routine) (void *), void *arg) { - GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false); - AsanThread *curr_thread = asanThreadRegistry().GetCurrent(); - CHECK(curr_thread || asanThreadRegistry().IsCurrentThreadDying()); - int current_tid = asanThreadRegistry().GetCurrentTidOrMinusOne(); - AsanThread *t = AsanThread::Create(current_tid, start_routine, arg); - asanThreadRegistry().RegisterThread(t, current_tid, &stack); - return real_pthread_create(thread, attr, asan_thread_start, t); -} - -static bool MySignal(int signum) { - if (FLAG_handle_segv && signum == SIGSEGV) return true; -#ifdef __APPLE__ - if (FLAG_handle_segv && signum == SIGBUS) return true; -#endif - return false; -} - -static void MaybeInstallSigaction(int signum, - void (*handler)(int, siginfo_t *, void *)) { - if (!MySignal(signum)) - return; - struct sigaction sigact; - real_memset(&sigact, 0, sizeof(sigact)); - sigact.sa_sigaction = handler; - sigact.sa_flags = SA_SIGINFO; - CHECK(0 == real_sigaction(signum, &sigact, 0)); -} - -extern "C" -sig_t WRAP(signal)(int signum, sig_t handler) { - if (!MySignal(signum)) { - return real_signal(signum, handler); - } - return NULL; -} - -extern "C" -int WRAP(sigaction)(int signum, const struct sigaction *act, - struct sigaction *oldact) { - if (!MySignal(signum)) { - return real_sigaction(signum, act, oldact); - } - return 0; -} - - -static void UnpoisonStackFromHereToTop() { - int local_stack; - AsanThread *curr_thread = asanThreadRegistry().GetCurrent(); - CHECK(curr_thread); - uintptr_t top = curr_thread->stack_top(); - uintptr_t bottom = ((uintptr_t)&local_stack - kPageSize) & ~(kPageSize-1); - PoisonShadow(bottom, top - bottom, 0); -} - -extern "C" void WRAP(longjmp)(void *env, int val) { - UnpoisonStackFromHereToTop(); - real_longjmp(env, val); -} - -extern "C" void WRAP(_longjmp)(void *env, int val) { - UnpoisonStackFromHereToTop(); - real__longjmp(env, val); -} - -extern "C" void WRAP(siglongjmp)(void *env, int val) { - UnpoisonStackFromHereToTop(); - real_siglongjmp(env, val); -} - -extern "C" void __cxa_throw(void *a, void *b, void *c); - -#if ASAN_HAS_EXCEPTIONS == 1 -extern "C" void WRAP(__cxa_throw)(void *a, void *b, void *c) { - CHECK(&real___cxa_throw); - UnpoisonStackFromHereToTop(); - real___cxa_throw(a, b, c); -} -#endif - -extern "C" { -// intercept mlock and friends. -// Since asan maps 16T of RAM, mlock is completely unfriendly to asan. -// All functions return 0 (success). -static void MlockIsUnsupported() { - static bool printed = 0; - if (printed) return; - printed = true; - Printf("INFO: AddressSanitizer ignores mlock/mlockall/munlock/munlockall\n"); -} -int mlock(const void *addr, size_t len) { - MlockIsUnsupported(); - return 0; -} -int munlock(const void *addr, size_t len) { - MlockIsUnsupported(); - return 0; -} -int mlockall(int flags) { - MlockIsUnsupported(); - return 0; -} -int munlockall(void) { - MlockIsUnsupported(); - return 0; -} -} // extern "C" - -// ---------------------- Interface ---------------- {{{1 int __asan_set_error_exit_code(int exit_code) { int old = FLAG_exitcode; FLAG_exitcode = exit_code; @@ -655,30 +480,6 @@ void __asan_init() { ReplaceSystemMalloc(); - INTERCEPT_FUNCTION(sigaction); - INTERCEPT_FUNCTION(signal); - INTERCEPT_FUNCTION(longjmp); - INTERCEPT_FUNCTION(_longjmp); - INTERCEPT_FUNCTION_IF_EXISTS(__cxa_throw); - INTERCEPT_FUNCTION(pthread_create); -#ifdef __APPLE__ - INTERCEPT_FUNCTION(dispatch_async_f); - INTERCEPT_FUNCTION(dispatch_sync_f); - INTERCEPT_FUNCTION(dispatch_after_f); - INTERCEPT_FUNCTION(dispatch_barrier_async_f); - INTERCEPT_FUNCTION(dispatch_group_async_f); - // We don't need to intercept pthread_workqueue_additem_np() to support the - // libdispatch API, but it helps us to debug the unsupported functions. Let's - // intercept it only during verbose runs. - if (FLAG_v >= 2) { - INTERCEPT_FUNCTION(pthread_workqueue_additem_np); - } -#else - // On Darwin siglongjmp tailcalls longjmp, so we don't want to intercept it - // there. - INTERCEPT_FUNCTION(siglongjmp); -#endif - MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV); MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV);