Index: lib/tsan/rtl/tsan_rtl_report.cc =================================================================== --- lib/tsan/rtl/tsan_rtl_report.cc +++ lib/tsan/rtl/tsan_rtl_report.cc @@ -694,26 +694,36 @@ PrintStack(SymbolizeStack(trace)); } -// 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 -// __sanitizer_print_stack_trace disappears after tail-call. -// However, this solution is not reliable enough, please see dvyukov's comment -// http://reviews.llvm.org/D19148#406208 -// Also see PR27280 comment 2 and 3 for breaking examples and analysis. -ALWAYS_INLINE -void PrintCurrentStackSlow(uptr pc) { #if !SANITIZER_GO +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(kStackTraceMax, pc, 0, 0, 0, 0, false); + ptrace->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, + request_fast_unwind); 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)); +} +#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 +// __sanitizer_print_stack_trace disappears after tail-call. +// However, this solution is not reliable enough, please see dvyukov's comment +// http://reviews.llvm.org/D19148#406208 +// Also see PR27280 comment 2 and 3 for breaking examples and analysis. +ALWAYS_INLINE +void PrintCurrentStackSlow(uptr pc) { +#if !SANITIZER_GO + PrintStackTrace(kStackTraceMax, pc, 0, nullptr, 0, 0, false); #endif } @@ -724,6 +734,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,20 @@ +// Test for __sanitizer_print_stack_trace implementation. + +// RUN: %clangxx_tsan -O0 %s -o %t +// RUN: TSAN_OPTIONS=stack_trace_format=DEFAULT:fast_unwind_on_fatal=0 %run %t 2>&1 | FileCheck %s +// RUN: 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{{.*}}print_stack_trace.cc:[[@LINE-9]] +// CHECK-FAST-UNWIND: {{.*}} in main{{.*}}print_stack_trace.cc:[[@LINE-6]]