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; @@ -57,8 +48,6 @@ 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; } 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{{.*}}