Index: lib/asan/asan_posix.cc =================================================================== --- lib/asan/asan_posix.cc +++ lib/asan/asan_posix.cc @@ -33,6 +33,7 @@ namespace __asan { void AsanOnSIGSEGV(int, void *siginfo, void *context) { + ScopedDeadlySignal signal_scope(GetCurrentThread()); uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr; int code = (int)((siginfo_t*)siginfo)->si_code; // Write the first message using the bullet-proof write. Index: lib/asan/asan_stack.h =================================================================== --- lib/asan/asan_stack.h +++ lib/asan/asan_stack.h @@ -35,6 +35,10 @@ stack->size = 0; if (LIKELY(asan_inited)) { if ((t = GetCurrentThread()) && !t->isUnwinding()) { + // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace() + // yields the call stack of the signal's handler and not of the code + // that raised the signal (as it does on Linux). + if (SANITIZER_FREEBSD && t->isInDeadlySignal()) fast = true; uptr stack_top = t->stack_top(); uptr stack_bottom = t->stack_bottom(); ScopedUnwinding unwind_scope(t); Index: lib/asan/asan_thread.h =================================================================== --- lib/asan/asan_thread.h +++ lib/asan/asan_thread.h @@ -108,6 +108,10 @@ bool isUnwinding() const { return unwinding_; } void setUnwinding(bool b) { unwinding_ = b; } + // True if we are in a deadly signal handler. + bool isInDeadlySignal() const { return in_deadly_signal_; } + void setInDeadlySignal(bool b) { in_deadly_signal_ = b; } + AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; } AsanStats &stats() { return stats_; } @@ -133,6 +137,7 @@ AsanThreadLocalMallocStorage malloc_storage_; AsanStats stats_; bool unwinding_; + bool in_deadly_signal_; }; // ScopedUnwinding is a scope for stacktracing member of a context @@ -147,6 +152,20 @@ AsanThread *thread; }; +// ScopedDeadlySignal is a scope for handling deadly signals. +class ScopedDeadlySignal { + public: + explicit ScopedDeadlySignal(AsanThread *t) : thread(t) { + if (thread) thread->setInDeadlySignal(true); + } + ~ScopedDeadlySignal() { + if (thread) thread->setInDeadlySignal(false); + } + + private: + AsanThread *thread; +}; + struct CreateThreadContextArgs { AsanThread *thread; StackTrace *stack; Index: lib/sanitizer_common/sanitizer_stacktrace.h =================================================================== --- lib/sanitizer_common/sanitizer_stacktrace.h +++ lib/sanitizer_common/sanitizer_stacktrace.h @@ -29,6 +29,13 @@ # define SANITIZER_CAN_FAST_UNWIND 1 #endif +// Fast unwind is the only option on Mac. +#if SANITIZER_MAC +# define SANITIZER_CAN_SLOW_UNWIND 0 +#else +# define SANITIZER_CAN_SLOW_UNWIND 1 +#endif + struct StackTrace { const uptr *trace; uptr size; @@ -40,13 +47,9 @@ void Print() const; static bool WillUseFastUnwind(bool request_fast_unwind) { - // Check if fast unwind is available. Fast unwind is the only option on Mac. - // It is also the only option on FreeBSD as the slow unwinding that - // leverages _Unwind_Backtrace() yields the call stack of the signal's - // handler and not of the code that raised the signal (as it does on Linux). if (!SANITIZER_CAN_FAST_UNWIND) return false; - else if (SANITIZER_MAC != 0 || SANITIZER_FREEBSD != 0) + else if (!SANITIZER_CAN_SLOW_UNWIND) return true; return request_fast_unwind; }