Index: lib/msan/msan.cc =================================================================== --- lib/msan/msan.cc +++ lib/msan/msan.cc @@ -220,7 +220,7 @@ void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp, bool request_fast_unwind) { MsanThread *t = GetCurrentThread(); - if (!t || !StackTrace::WillUseFastUnwind(request_fast_unwind)) { + if (!t || !request_fast_unwind) { // Block reports from our interceptors during _Unwind_Backtrace. SymbolizerScope sym_scope; return stack->Unwind(max_s, pc, bp, nullptr, 0, 0, request_fast_unwind); Index: lib/sanitizer_common/sanitizer_stacktrace.h =================================================================== --- lib/sanitizer_common/sanitizer_stacktrace.h +++ lib/sanitizer_common/sanitizer_stacktrace.h @@ -27,15 +27,6 @@ # define SANITIZER_CAN_FAST_UNWIND 1 #endif -// Fast unwind is the only option on Mac for now; we will need to -// revisit this macro when slow unwind works on Mac, see -// https://github.com/google/sanitizers/issues/137 -#if SANITIZER_MAC -# define SANITIZER_CAN_SLOW_UNWIND 0 -#else -# define SANITIZER_CAN_SLOW_UNWIND 1 -#endif - struct StackTrace { const uptr *trace; u32 size; @@ -54,14 +45,6 @@ // Prints a symbolized stacktrace, followed by an empty line. void Print() const; - static bool WillUseFastUnwind(bool request_fast_unwind) { - if (!SANITIZER_CAN_FAST_UNWIND) - return false; - else if (!SANITIZER_CAN_SLOW_UNWIND) - return true; - return request_fast_unwind; - } - static uptr GetCurrentPc(); static inline uptr GetPreviousInstructionPc(uptr pc); static uptr GetNextInstructionPc(uptr pc); Index: lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc +++ lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc @@ -68,7 +68,7 @@ trace_buffer[0] = pc; return; } - if (!WillUseFastUnwind(request_fast_unwind)) { + if (!request_fast_unwind) { #if SANITIZER_CAN_SLOW_UNWIND if (context) SlowUnwindStackWithContext(pc, context, max_depth); Index: lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc =================================================================== --- lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc +++ lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc @@ -22,8 +22,6 @@ virtual void SetUp(); virtual void TearDown(); bool TryFastUnwind(uptr max_depth) { - if (!StackTrace::WillUseFastUnwind(true)) - return false; trace.Unwind(max_depth, start_pc, (uptr)&fake_stack[0], 0, fake_top, fake_bottom, true); return true; @@ -150,8 +148,6 @@ } TEST(SlowUnwindTest, ShortStackTrace) { - if (StackTrace::WillUseFastUnwind(false)) - return; BufferedStackTrace stack; uptr pc = StackTrace::GetCurrentPc(); uptr bp = GET_CURRENT_FRAME(); Index: lib/tsan/rtl/tsan_rtl_report.cc =================================================================== --- lib/tsan/rtl/tsan_rtl_report.cc +++ lib/tsan/rtl/tsan_rtl_report.cc @@ -694,6 +694,29 @@ PrintStack(SymbolizeStack(trace)); } +#if !SANITIZER_GO +static inline void ReverseStackTrace(BufferedStackTrace *ptrace) { + for (uptr i = 0; i < ptrace->size / 2; i++) { + uptr tmp = ptrace->trace_buffer[i]; + ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1]; + ptrace->trace_buffer[ptrace->size - i - 1] = tmp; + } +} + +static inline void PrintStackTrace(u32 max_depth, uptr pc, uptr bp, + void *context, uptr stack_top, + uptr stack_bottom, + bool request_fast_unwind) { + BufferedStackTrace *ptrace = + new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace))) + BufferedStackTrace(); + ptrace->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, + request_fast_unwind); + ReverseStackTrace(ptrace); + PrintStack(SymbolizeStack(*ptrace)); +} +#endif + // Always inlining PrintCurrentStackSlow, because LocatePcInTrace assumes // __sanitizer_print_stack_trace exists in the actual unwinded stack, but // tail-call to PrintCurrentStackSlow breaks this assumption because @@ -704,16 +727,7 @@ ALWAYS_INLINE void PrintCurrentStackSlow(uptr pc) { #if !SANITIZER_GO - BufferedStackTrace *ptrace = - new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace))) - BufferedStackTrace(); - ptrace->Unwind(kStackTraceMax, pc, 0, 0, 0, 0, false); - for (uptr i = 0; i < ptrace->size / 2; i++) { - uptr tmp = ptrace->trace_buffer[i]; - ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1]; - ptrace->trace_buffer[ptrace->size - i - 1] = tmp; - } - PrintStack(SymbolizeStack(*ptrace)); + PrintStackTrace(kStackTraceMax, pc, 0, nullptr, 0, 0, false); #endif } @@ -724,6 +738,20 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_print_stack_trace() { - PrintCurrentStackSlow(StackTrace::GetCurrentPc()); +#if !SANITIZER_GO + uptr pc = StackTrace::GetCurrentPc(); + bool request_fast_unwind = common_flags()->fast_unwind_on_fatal; + if (!request_fast_unwind) { + PrintCurrentStackSlow(pc); + return; + } + + uptr top = 0; + uptr bottom = 0; + __sanitizer::GetThreadStackTopAndBottom(false, &top, &bottom); + uptr bp = GET_CURRENT_FRAME(); + PrintStackTrace(kStackTraceMax, pc, bp, nullptr, top, bottom, + request_fast_unwind); +#endif } } // extern "C" Index: test/tsan/print_stack_trace.cc =================================================================== --- /dev/null +++ test/tsan/print_stack_trace.cc @@ -0,0 +1,19 @@ +// Test for __sanitizer_print_stack_trace implementation. + +// RUN: %clangxx_tsan -O0 %s -o %t && TSAN_OPTIONS=stack_trace_format=DEFAULT:fast_unwind_on_fatal=0 %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_tsan -O0 %s -o %t && TSAN_OPTIONS=stack_trace_format=DEFAULT:fast_unwind_on_fatal=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST-UNWIND + +#include + +static inline void FooBarBaz() { + __sanitizer_print_stack_trace(); +} + +int main() { + FooBarBaz(); + return 0; +} + +// CHECK: {{.*}} in __sanitizer_print_stack_trace{{.*}} +// CHECK-FAST-UNWIND: {{.*}} in FooBarBaz{{.*}} +// CHECK-FAST-UNWIND: {{.*}} in main{{.*}}