[asan] refactoring: move all interceptors to a single file

llvm-svn: 147784
This commit is contained in:
Kostya Serebryany 2012-01-09 18:53:15 +00:00
parent 12ea3c56c3
commit 9fd01e5ea5
6 changed files with 206 additions and 209 deletions

View File

@ -19,7 +19,9 @@
#include "asan_mapping.h"
#include "asan_stack.h"
#include "asan_stats.h"
#include "asan_thread_registry.h"
#include <new>
#include <ctype.h>
#include <dlfcn.h>
#include <string.h>
@ -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;
}

View File

@ -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);

View File

@ -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().

View File

@ -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

View File

@ -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);

View File

@ -24,19 +24,9 @@
#include "asan_thread.h"
#include "asan_thread_registry.h"
#include <new>
#include <dlfcn.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
// must not include <setjmp.h> 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);