diff --git a/compiler-rt/lib/asan/asan_stack.cpp b/compiler-rt/lib/asan/asan_stack.cpp --- a/compiler-rt/lib/asan/asan_stack.cpp +++ b/compiler-rt/lib/asan/asan_stack.cpp @@ -74,7 +74,8 @@ if (SANITIZER_MIPS && t && !IsValidFrame(bp, t->stack_top(), t->stack_bottom())) return; - Unwind(max_depth, pc, bp, context, 0, 0, false); + Unwind(max_depth, pc, bp, context, t ? t->stack_top() : 0, + t ? t->stack_bottom() : 0, false); } // ------------------ Interface -------------- {{{1 diff --git a/compiler-rt/lib/lsan/lsan.cpp b/compiler-rt/lib/lsan/lsan.cpp --- a/compiler-rt/lib/lsan/lsan.cpp +++ b/compiler-rt/lib/lsan/lsan.cpp @@ -35,18 +35,14 @@ uptr pc, uptr bp, void *context, bool request_fast, u32 max_depth) { using namespace __lsan; uptr stack_top = 0, stack_bottom = 0; - ThreadContext *t; - if (StackTrace::WillUseFastUnwind(request_fast) && - (t = CurrentThreadContext())) { + if (ThreadContext *t = CurrentThreadContext()) { stack_top = t->stack_end(); stack_bottom = t->stack_begin(); } - if (!SANITIZER_MIPS || IsValidFrame(bp, stack_top, stack_bottom)) { - if (StackTrace::WillUseFastUnwind(request_fast)) - Unwind(max_depth, pc, bp, nullptr, stack_top, stack_bottom, true); - else - Unwind(max_depth, pc, 0, context, 0, 0, false); - } + if (SANITIZER_MIPS && !IsValidFrame(bp, stack_top, stack_bottom)) + return; + bool fast = StackTrace::WillUseFastUnwind(request_fast); + Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, fast); } using namespace __lsan; diff --git a/compiler-rt/lib/msan/msan.cpp b/compiler-rt/lib/msan/msan.cpp --- a/compiler-rt/lib/msan/msan.cpp +++ b/compiler-rt/lib/msan/msan.cpp @@ -308,7 +308,8 @@ if (!t || !StackTrace::WillUseFastUnwind(request_fast)) { // Block reports from our interceptors during _Unwind_Backtrace. SymbolizerScope sym_scope; - return Unwind(max_depth, pc, bp, context, 0, 0, false); + return Unwind(max_depth, pc, bp, context, t ? t->stack_top() : 0, + t ? t->stack_bottom() : 0, false); } if (StackTrace::WillUseFastUnwind(request_fast)) Unwind(max_depth, pc, bp, nullptr, t->stack_top(), t->stack_bottom(), true); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp @@ -82,12 +82,15 @@ UnwindSlow(pc, context, max_depth); else UnwindSlow(pc, max_depth); + // If there are too few frames, the program may be built with + // -fno-asynchronous-unwind-tables. Fall back to fast unwinder below. + if (size > 2) + return; #else UNREACHABLE("slow unwind requested but not available"); #endif - } else { - UnwindFast(pc, bp, stack_top, stack_bottom, max_depth); } + UnwindFast(pc, bp, stack_top, stack_bottom, max_depth); } static int GetModuleAndOffsetForPc(uptr pc, char *module_name, diff --git a/compiler-rt/lib/tsan/rtl/tsan_stack_trace.cpp b/compiler-rt/lib/tsan/rtl/tsan_stack_trace.cpp --- a/compiler-rt/lib/tsan/rtl/tsan_stack_trace.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_stack_trace.cpp @@ -54,10 +54,8 @@ uptr pc, uptr bp, void *context, bool request_fast, u32 max_depth) { uptr top = 0; uptr bottom = 0; - if (StackTrace::WillUseFastUnwind(request_fast)) { - GetThreadStackTopAndBottom(false, &top, &bottom); - Unwind(max_depth, pc, bp, nullptr, top, bottom, true); - } else - Unwind(max_depth, pc, 0, context, 0, 0, false); + GetThreadStackTopAndBottom(false, &top, &bottom); + bool fast = StackTrace::WillUseFastUnwind(request_fast); + Unwind(max_depth, pc, bp, context, top, bottom, fast); } #endif // SANITIZER_GO diff --git a/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp b/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp --- a/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp +++ b/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp @@ -20,11 +20,9 @@ uptr pc, uptr bp, void *context, bool request_fast, u32 max_depth) { uptr top = 0; uptr bottom = 0; - if (StackTrace::WillUseFastUnwind(request_fast)) { - GetThreadStackTopAndBottom(false, &top, &bottom); - Unwind(max_depth, pc, bp, nullptr, top, bottom, true); - } else - Unwind(max_depth, pc, bp, context, 0, 0, false); + GetThreadStackTopAndBottom(false, &top, &bottom); + bool fast = StackTrace::WillUseFastUnwind(request_fast); + Unwind(max_depth, pc, bp, context, top, bottom, fast); } extern "C" { diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/symbolize_stack_fp.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/symbolize_stack_fp.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/symbolize_stack_fp.cpp @@ -0,0 +1,35 @@ +/// When the main program doesn't use .eh_frame, the slow unwinder does not work. +/// Test that we can fall back to the fast unwinder. +// RUN: %clangxx -O0 -g1 -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer %s -o %t +// RUN: llvm-readelf -S %t | FileCheck %s --check-prefix=SEC +// RUN: %run %t 2>&1 | FileCheck %s + +/// No .eh_frame && -g => .debug_frame +// SEC: .debug_frame + +#include +#include + +template +struct A { + template + void RecursiveTemplateFunction(const T &t); +}; + +template +template +__attribute__((noinline)) void A::RecursiveTemplateFunction(const T &) { + std::vector t; + return A().RecursiveTemplateFunction(t); +} + +template <> +template +__attribute__((noinline)) void A<0>::RecursiveTemplateFunction(const T &) { + __sanitizer_print_stack_trace(); +} + +int main() { + // CHECK: {{vector<.*vector<.*vector<.*vector<.*vector<}} + A<10>().RecursiveTemplateFunction(0); +}