From baf583c443e6fa9467fe3169afd5f4c4e51c219b Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 13 Dec 2012 09:34:23 +0000 Subject: [PATCH] [asan] add two asan flags: fast_unwind_on_fatal and fast_unwind_on_malloc to allow using the slow CFI-based unwinder llvm-svn: 170117 --- compiler-rt/lib/asan/asan_allocator.cc | 2 +- compiler-rt/lib/asan/asan_flags.h | 6 ++- compiler-rt/lib/asan/asan_interceptors.cc | 6 +-- compiler-rt/lib/asan/asan_linux.cc | 50 ++++--------------- compiler-rt/lib/asan/asan_mac.cc | 16 +++--- compiler-rt/lib/asan/asan_malloc_linux.cc | 20 ++++---- compiler-rt/lib/asan/asan_malloc_mac.cc | 28 +++++------ compiler-rt/lib/asan/asan_malloc_win.cc | 10 ++-- compiler-rt/lib/asan/asan_new_delete.cc | 4 +- compiler-rt/lib/asan/asan_report.cc | 4 +- compiler-rt/lib/asan/asan_rtl.cc | 4 ++ compiler-rt/lib/asan/asan_stack.h | 32 ++++++++---- .../lib/sanitizer_common/sanitizer_linux.cc | 43 ++++++++++++++++ .../sanitizer_common/sanitizer_stacktrace.h | 1 + 14 files changed, 129 insertions(+), 97 deletions(-) diff --git a/compiler-rt/lib/asan/asan_allocator.cc b/compiler-rt/lib/asan/asan_allocator.cc index 484f9e12641f..b6ae3c84bd03 100644 --- a/compiler-rt/lib/asan/asan_allocator.cc +++ b/compiler-rt/lib/asan/asan_allocator.cc @@ -819,7 +819,7 @@ uptr __asan_get_allocated_size(const void *p) { uptr allocated_size = malloc_info.AllocationSize((uptr)p); // Die if p is not malloced or if it is already freed. if (allocated_size == 0) { - GET_STACK_TRACE_HERE(kStackTraceMax); + GET_STACK_TRACE_FATAL_HERE; ReportAsanGetAllocatedSizeNotOwned((uptr)p, &stack); } return allocated_size; diff --git a/compiler-rt/lib/asan/asan_flags.h b/compiler-rt/lib/asan/asan_flags.h index 989784df036c..ded2b24c82cb 100644 --- a/compiler-rt/lib/asan/asan_flags.h +++ b/compiler-rt/lib/asan/asan_flags.h @@ -45,7 +45,7 @@ struct Flags { int report_globals; // If set, attempts to catch initialization order issues. bool check_initialization_order; - // Max number of stack frames kept for each allocation. + // Max number of stack frames kept for each allocation/deallocation. int malloc_context_size; // If set, uses custom wrappers and replacements for libc string functions // to find more errors. @@ -95,6 +95,10 @@ struct Flags { bool print_full_thread_history; // ASan will write logs to "log_path.pid" instead of stderr. const char *log_path; + // Use fast (frame-pointer-based) unwinder on fatal errors (if available). + bool fast_unwind_on_fatal; + // Use fast (frame-pointer-based) unwinder on malloc/free (if available). + bool fast_unwind_on_malloc; }; Flags *flags(); diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc index 595f0ed3f683..d3969ed59769 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cc +++ b/compiler-rt/lib/asan/asan_interceptors.cc @@ -71,7 +71,7 @@ static inline bool RangesOverlap(const char *offset1, uptr length1, const char *offset1 = (const char*)_offset1; \ const char *offset2 = (const char*)_offset2; \ if (RangesOverlap(offset1, length1, offset2, length2)) { \ - GET_STACK_TRACE_HERE(kStackTraceMax); \ + GET_STACK_TRACE_FATAL_HERE; \ ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \ offset2, length2, &stack); \ } \ @@ -112,7 +112,7 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { #if ASAN_INTERCEPT_PTHREAD_CREATE INTERCEPTOR(int, pthread_create, void *thread, void *attr, void *(*start_routine)(void*), void *arg) { - GET_STACK_TRACE_HERE(kStackTraceMax); + GET_STACK_TRACE_THREAD; u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack); asanThreadRegistry().RegisterThread(t); @@ -647,7 +647,7 @@ INTERCEPTOR_WINAPI(DWORD, CreateThread, void* security, uptr stack_size, DWORD (__stdcall *start_routine)(void*), void* arg, DWORD flags, void* tid) { - GET_STACK_TRACE_HERE(kStackTraceMax); + GET_STACK_TRACE_THREAD; u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack); asanThreadRegistry().RegisterThread(t); diff --git a/compiler-rt/lib/asan/asan_linux.cc b/compiler-rt/lib/asan/asan_linux.cc index 068f7b100b29..02a3d144c85d 100644 --- a/compiler-rt/lib/asan/asan_linux.cc +++ b/compiler-rt/lib/asan/asan_linux.cc @@ -122,53 +122,21 @@ void AsanLock::Unlock() { pthread_mutex_unlock((pthread_mutex_t*)&opaque_storage_); } -#ifdef __arm__ -#define UNWIND_STOP _URC_END_OF_STACK -#define UNWIND_CONTINUE _URC_NO_REASON -#else -#define UNWIND_STOP _URC_NORMAL_STOP -#define UNWIND_CONTINUE _URC_NO_REASON -#endif - -uptr Unwind_GetIP(struct _Unwind_Context *ctx) { -#ifdef __arm__ - uptr val; - _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE, - 15 /* r15 = PC */, _UVRSD_UINT32, &val); - CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed"); - // Clear the Thumb bit. - return val & ~(uptr)1; -#else - return _Unwind_GetIP(ctx); -#endif -} - -_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, - void *param) { - StackTrace *b = (StackTrace*)param; - CHECK(b->size < b->max_size); - uptr pc = Unwind_GetIP(ctx); - b->trace[b->size++] = pc; - if (b->size == b->max_size) return UNWIND_STOP; - return UNWIND_CONTINUE; -} - -void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp) { - stack->size = 0; - stack->trace[0] = pc; - if ((max_s) > 1) { - stack->max_size = max_s; +void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) { #if defined(__arm__) || \ defined(__powerpc__) || defined(__powerpc64__) || \ defined(__sparc__) - _Unwind_Backtrace(Unwind_Trace, stack); - // Pop off the two ASAN functions from the backtrace. - stack->PopStackFrames(2); -#else + fast = false; +#endif + if (!fast) + return stack->SlowUnwindStack(pc, max_s, 3); + stack->size = 0; + stack->trace[0] = pc; + if (max_s > 1) { + stack->max_size = max_s; if (!asan_inited) return; if (AsanThread *t = asanThreadRegistry().GetCurrent()) stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom()); -#endif } } diff --git a/compiler-rt/lib/asan/asan_mac.cc b/compiler-rt/lib/asan/asan_mac.cc index 7abe9a429258..11e6a13a8e5c 100644 --- a/compiler-rt/lib/asan/asan_mac.cc +++ b/compiler-rt/lib/asan/asan_mac.cc @@ -160,7 +160,7 @@ void AsanLock::Unlock() { OSSpinLockUnlock((OSSpinLock*)&opaque_storage_); } -void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp) { +void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) { stack->size = 0; stack->trace[0] = pc; if ((max_s) > 1) { @@ -308,7 +308,7 @@ void asan_register_worker_thread(int parent_tid, StackTrace *stack) { // alloc_asan_context(). extern "C" void asan_dispatch_call_block_and_release(void *block) { - GET_STACK_TRACE_HERE(kStackTraceMax); + GET_STACK_TRACE_THREAD; asan_block_context_t *context = (asan_block_context_t*)block; if (flags()->verbosity >= 2) { Report("asan_dispatch_call_block_and_release(): " @@ -343,7 +343,7 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func, #define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \ INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \ dispatch_function_t func) { \ - GET_STACK_TRACE_HERE(kStackTraceMax); \ + GET_STACK_TRACE_THREAD; \ asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \ if (flags()->verbosity >= 2) { \ Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \ @@ -361,7 +361,7 @@ INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f) INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, dispatch_queue_t dq, void *ctxt, dispatch_function_t func) { - GET_STACK_TRACE_HERE(kStackTraceMax); + GET_STACK_TRACE_THREAD; asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); if (flags()->verbosity >= 2) { Report("dispatch_after_f: %p\n", asan_ctxt); @@ -374,7 +374,7 @@ INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, dispatch_queue_t dq, void *ctxt, dispatch_function_t func) { - GET_STACK_TRACE_HERE(kStackTraceMax); + GET_STACK_TRACE_THREAD; asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); if (flags()->verbosity >= 2) { Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n", @@ -409,7 +409,7 @@ void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void)); void (^asan_block)(void); \ int parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); \ asan_block = ^(void) { \ - GET_STACK_TRACE_HERE(kStackTraceMax); \ + GET_STACK_TRACE_THREAD; \ asan_register_worker_thread(parent_tid, &stack); \ work(); \ } @@ -459,7 +459,7 @@ void *wrap_workitem_func(void *arg) { asan_block_context_t *ctxt = (asan_block_context_t*)arg; worker_t fn = (worker_t)(ctxt->func); void *result = fn(ctxt->block); - GET_STACK_TRACE_HERE(kStackTraceMax); + GET_STACK_TRACE_THREAD; asan_free(arg, &stack); return result; } @@ -467,7 +467,7 @@ void *wrap_workitem_func(void *arg) { INTERCEPTOR(int, pthread_workqueue_additem_np, pthread_workqueue_t workq, void *(*workitem_func)(void *), void * workitem_arg, pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp) { - GET_STACK_TRACE_HERE(kStackTraceMax); + GET_STACK_TRACE_THREAD; asan_block_context_t *asan_ctxt = (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), &stack); asan_ctxt->block = workitem_arg; diff --git a/compiler-rt/lib/asan/asan_malloc_linux.cc b/compiler-rt/lib/asan/asan_malloc_linux.cc index 5eb23ddbc440..1bf90518fabf 100644 --- a/compiler-rt/lib/asan/asan_malloc_linux.cc +++ b/compiler-rt/lib/asan/asan_malloc_linux.cc @@ -59,17 +59,17 @@ void ReplaceSystemMalloc() { using namespace __asan; // NOLINT INTERCEPTOR(void, free, void *ptr) { - GET_STACK_TRACE_HERE_FOR_FREE(ptr); + GET_STACK_TRACE_FREE; asan_free(ptr, &stack); } INTERCEPTOR(void, cfree, void *ptr) { - GET_STACK_TRACE_HERE_FOR_FREE(ptr); + GET_STACK_TRACE_FREE; asan_free(ptr, &stack); } INTERCEPTOR(void*, malloc, uptr size) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } @@ -85,17 +85,17 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { CHECK(allocated < kCallocPoolSize); return mem; } - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_calloc(nmemb, size, &stack); } INTERCEPTOR(void*, realloc, void *ptr, uptr size) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_realloc(ptr, size, &stack); } INTERCEPTOR(void*, memalign, uptr boundary, uptr size) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_memalign(boundary, size, &stack); } @@ -103,7 +103,7 @@ INTERCEPTOR(void*, __libc_memalign, uptr align, uptr s) ALIAS("memalign"); INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_malloc_usable_size(ptr, &stack); } @@ -126,18 +126,18 @@ INTERCEPTOR(int, mallopt, int cmd, int value) { } INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; // Printf("posix_memalign: %zx %zu\n", alignment, size); return asan_posix_memalign(memptr, alignment, size, &stack); } INTERCEPTOR(void*, valloc, uptr size) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_valloc(size, &stack); } INTERCEPTOR(void*, pvalloc, uptr size) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_pvalloc(size, &stack); } diff --git a/compiler-rt/lib/asan/asan_malloc_mac.cc b/compiler-rt/lib/asan/asan_malloc_mac.cc index b32c18ef2d9c..15d166d28d16 100644 --- a/compiler-rt/lib/asan/asan_malloc_mac.cc +++ b/compiler-rt/lib/asan/asan_malloc_mac.cc @@ -92,7 +92,7 @@ INTERCEPTOR(void, free, void *ptr) { #endif } else { if (!asan_mz_size(ptr)) ptr = get_saved_cfallocator_ref(ptr); - GET_STACK_TRACE_HERE_FOR_FREE(ptr); + GET_STACK_TRACE_FREE; asan_free(ptr, &stack); } } @@ -130,7 +130,7 @@ void *mz_malloc(malloc_zone_t *zone, size_t size) { CHECK(system_malloc_zone); return malloc_zone_malloc(system_malloc_zone, size); } - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } @@ -139,7 +139,7 @@ void *cf_malloc(CFIndex size, CFOptionFlags hint, void *info) { CHECK(system_malloc_zone); return malloc_zone_malloc(system_malloc_zone, size); } - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } @@ -155,7 +155,7 @@ void *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) { CHECK(allocated < kCallocPoolSize); return mem; } - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_calloc(nmemb, size, &stack); } @@ -164,7 +164,7 @@ void *mz_valloc(malloc_zone_t *zone, size_t size) { CHECK(system_malloc_zone); return malloc_zone_valloc(system_malloc_zone, size); } - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_memalign(GetPageSizeCached(), size, &stack); } @@ -175,7 +175,7 @@ void *mz_valloc(malloc_zone_t *zone, size_t size) { void ALWAYS_INLINE free_common(void *context, void *ptr) { if (!ptr) return; if (asan_mz_size(ptr)) { - GET_STACK_TRACE_HERE_FOR_FREE(ptr); + GET_STACK_TRACE_FREE; asan_free(ptr, &stack); } else { // If the pointer does not belong to any of the zones, use one of the @@ -190,7 +190,7 @@ void ALWAYS_INLINE free_common(void *context, void *ptr) { // If the memory chunk pointer was moved to store additional // CFAllocatorRef, fix it back. ptr = get_saved_cfallocator_ref(ptr); - GET_STACK_TRACE_HERE_FOR_FREE(ptr); + GET_STACK_TRACE_FREE; if (!flags()->mac_ignore_invalid_free) { asan_free(ptr, &stack); } else { @@ -213,17 +213,17 @@ void cf_free(void *ptr, void *info) { void *mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) { if (!ptr) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } else { if (asan_mz_size(ptr)) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_realloc(ptr, size, &stack); } else { // We can't recover from reallocating an unknown address, because // this would require reading at most |size| bytes from // potentially unaccessible memory. - GET_STACK_TRACE_HERE_FOR_FREE(ptr); + GET_STACK_TRACE_FREE; GET_ZONE_FOR_PTR(ptr); ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack); } @@ -232,17 +232,17 @@ void *mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) { void *cf_realloc(void *ptr, CFIndex size, CFOptionFlags hint, void *info) { if (!ptr) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } else { if (asan_mz_size(ptr)) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_realloc(ptr, size, &stack); } else { // We can't recover from reallocating an unknown address, because // this would require reading at most |size| bytes from // potentially unaccessible memory. - GET_STACK_TRACE_HERE_FOR_FREE(ptr); + ET_STACK_TRACE_FREE(ptr); GET_ZONE_FOR_PTR(ptr); ReportMacCfReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack); } @@ -261,7 +261,7 @@ void *mz_memalign(malloc_zone_t *zone, size_t align, size_t size) { CHECK(system_malloc_zone); return malloc_zone_memalign(system_malloc_zone, align, size); } - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_memalign(align, size, &stack); } diff --git a/compiler-rt/lib/asan/asan_malloc_win.cc b/compiler-rt/lib/asan/asan_malloc_win.cc index 3ec76d89caa2..0ddc3ca445d5 100644 --- a/compiler-rt/lib/asan/asan_malloc_win.cc +++ b/compiler-rt/lib/asan/asan_malloc_win.cc @@ -31,7 +31,7 @@ using namespace __asan; // NOLINT extern "C" { void free(void *ptr) { - GET_STACK_TRACE_HERE_FOR_FREE(ptr); + GET_STACK_TRACE_FREE; return asan_free(ptr, &stack); } @@ -44,7 +44,7 @@ void cfree(void *ptr) { } void *malloc(size_t size) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } @@ -53,7 +53,7 @@ void* _malloc_dbg(size_t size, int , const char*, int) { } void *calloc(size_t nmemb, size_t size) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_calloc(nmemb, size, &stack); } @@ -66,7 +66,7 @@ void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) { } void *realloc(void *ptr, size_t size) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_realloc(ptr, size, &stack); } @@ -85,7 +85,7 @@ void* _recalloc(void* p, size_t n, size_t elem_size) { } size_t _msize(void *ptr) { - GET_STACK_TRACE_HERE_FOR_MALLOC; + GET_STACK_TRACE_MALLOC; return asan_malloc_usable_size(ptr, &stack); } diff --git a/compiler-rt/lib/asan/asan_new_delete.cc b/compiler-rt/lib/asan/asan_new_delete.cc index 756810dc3186..e21aa452223b 100644 --- a/compiler-rt/lib/asan/asan_new_delete.cc +++ b/compiler-rt/lib/asan/asan_new_delete.cc @@ -36,7 +36,7 @@ struct nothrow_t {}; } // namespace std #define OPERATOR_NEW_BODY \ - GET_STACK_TRACE_HERE_FOR_MALLOC;\ + GET_STACK_TRACE_MALLOC;\ return asan_memalign(0, size, &stack); INTERCEPTOR_ATTRIBUTE @@ -49,7 +49,7 @@ INTERCEPTOR_ATTRIBUTE void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; } #define OPERATOR_DELETE_BODY \ - GET_STACK_TRACE_HERE_FOR_FREE(ptr);\ + GET_STACK_TRACE_FREE;\ asan_free(ptr, &stack); INTERCEPTOR_ATTRIBUTE diff --git a/compiler-rt/lib/asan/asan_report.cc b/compiler-rt/lib/asan/asan_report.cc index 558e4f202b4a..5ad9115657de 100644 --- a/compiler-rt/lib/asan/asan_report.cc +++ b/compiler-rt/lib/asan/asan_report.cc @@ -358,7 +358,7 @@ void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) { (void*)addr, (void*)pc, (void*)sp, (void*)bp, asanThreadRegistry().GetCurrentTidOrInvalid()); Printf("AddressSanitizer can not provide additional info.\n"); - GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp); + GET_STACK_TRACE_FATAL(pc, bp); PrintStack(&stack); } @@ -506,7 +506,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, access_size, (void*)addr, curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); - GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp); + GET_STACK_TRACE_FATAL(pc, bp); PrintStack(&stack); DescribeAddress(addr, access_size); diff --git a/compiler-rt/lib/asan/asan_rtl.cc b/compiler-rt/lib/asan/asan_rtl.cc index 37c9583a7c3f..e186d9515c4f 100644 --- a/compiler-rt/lib/asan/asan_rtl.cc +++ b/compiler-rt/lib/asan/asan_rtl.cc @@ -104,6 +104,8 @@ static void ParseFlagsFromString(Flags *f, const char *str) { ParseFlag(str, &f->allow_reexec, "allow_reexec"); ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history"); ParseFlag(str, &f->log_path, "log_path"); + ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal"); + ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc"); } void InitializeFlags(Flags *f, const char *env) { @@ -137,6 +139,8 @@ void InitializeFlags(Flags *f, const char *env) { f->allow_reexec = true; f->print_full_thread_history = true; f->log_path = 0; + f->fast_unwind_on_fatal = true; + f->fast_unwind_on_malloc = true; // Override from user-specified string. ParseFlagsFromString(f, MaybeCallAsanDefaultOptions()); diff --git a/compiler-rt/lib/asan/asan_stack.h b/compiler-rt/lib/asan/asan_stack.h index 99f2cac1485b..46c9f3408725 100644 --- a/compiler-rt/lib/asan/asan_stack.h +++ b/compiler-rt/lib/asan/asan_stack.h @@ -15,10 +15,11 @@ #define ASAN_STACK_H #include "sanitizer_common/sanitizer_stacktrace.h" +#include "asan_flags.h" namespace __asan { -void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp); +void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast); void PrintStack(StackTrace *stack); } // namespace __asan @@ -27,27 +28,38 @@ void PrintStack(StackTrace *stack); // The pc will be in the position 0 of the resulting stack trace. // The bp may refer to the current frame or to the caller's frame. // fast_unwind is currently unused. -#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp) \ +#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \ StackTrace stack; \ - GetStackTrace(&stack, max_s, pc, bp) + GetStackTrace(&stack, max_s, pc, bp, fast) // NOTE: A Rule of thumb is to retrieve stack trace in the interceptors // as early as possible (in functions exposed to the user), as we generally // don't want stack trace to contain functions from ASan internals. -#define GET_STACK_TRACE_HERE(max_size) \ +#define GET_STACK_TRACE(max_size, fast) \ GET_STACK_TRACE_WITH_PC_AND_BP(max_size, \ - StackTrace::GetCurrentPc(), GET_CURRENT_FRAME()) + StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), fast) -#define GET_STACK_TRACE_HERE_FOR_MALLOC \ - GET_STACK_TRACE_HERE(flags()->malloc_context_size) +#define GET_STACK_TRACE_FATAL(pc, bp) \ + GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp, \ + flags()->fast_unwind_on_fatal) -#define GET_STACK_TRACE_HERE_FOR_FREE(ptr) \ - GET_STACK_TRACE_HERE(flags()->malloc_context_size) +#define GET_STACK_TRACE_FATAL_HERE \ + GET_STACK_TRACE(kStackTraceMax, flags()->fast_unwind_on_fatal) + +#define GET_STACK_TRACE_THREAD \ + GET_STACK_TRACE(kStackTraceMax, true) + +#define GET_STACK_TRACE_MALLOC \ + GET_STACK_TRACE(flags()->malloc_context_size, \ + flags()->fast_unwind_on_malloc) + +#define GET_STACK_TRACE_FREE GET_STACK_TRACE_MALLOC #define PRINT_CURRENT_STACK() \ { \ - GET_STACK_TRACE_HERE(kStackTraceMax); \ + GET_STACK_TRACE(kStackTraceMax, \ + flags()->fast_unwind_on_fatal); \ PrintStack(&stack); \ } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc index 5be76e9e6a63..6a0f2615eee2 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc @@ -19,6 +19,7 @@ #include "sanitizer_mutex.h" #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" +#include "sanitizer_stacktrace.h" #include #include @@ -30,6 +31,7 @@ #include #include #include +#include #include #include @@ -378,6 +380,47 @@ bool SanitizerGetThreadName(char *name, int max_len) { return true; } +//------------------------- SlowUnwindStack ----------------------------------- +#ifdef __arm__ +#define UNWIND_STOP _URC_END_OF_STACK +#define UNWIND_CONTINUE _URC_NO_REASON +#else +#define UNWIND_STOP _URC_NORMAL_STOP +#define UNWIND_CONTINUE _URC_NO_REASON +#endif + +uptr Unwind_GetIP(struct _Unwind_Context *ctx) { +#ifdef __arm__ + uptr val; + _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE, + 15 /* r15 = PC */, _UVRSD_UINT32, &val); + CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed"); + // Clear the Thumb bit. + return val & ~(uptr)1; +#else + return _Unwind_GetIP(ctx); +#endif +} + +_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { + StackTrace *b = (StackTrace*)param; + CHECK(b->size < b->max_size); + uptr pc = Unwind_GetIP(ctx); + b->trace[b->size++] = pc; + if (b->size == b->max_size) return UNWIND_STOP; + return UNWIND_CONTINUE; +} + +void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth, uptr frames_to_pop) { + this->size = 0; + this->trace[0] = pc; + this->max_size = max_depth; + if (max_depth > 1) { + _Unwind_Backtrace(Unwind_Trace, this); + this->PopStackFrames(frames_to_pop); + } +} + } // namespace __sanitizer #endif // __linux__ diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h index fe2dcf064246..64979ec5a893 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h @@ -44,6 +44,7 @@ struct StackTrace { } void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom); + void SlowUnwindStack(uptr pc, uptr max_depth, uptr frames_to_pop); void PopStackFrames(uptr count);