diff --git a/compiler-rt/lib/asan/asan_stack.h b/compiler-rt/lib/asan/asan_stack.h --- a/compiler-rt/lib/asan/asan_stack.h +++ b/compiler-rt/lib/asan/asan_stack.h @@ -33,7 +33,7 @@ void GetStackTrace(BufferedStackTrace *stack, uptr max_depth, uptr pc, uptr bp, void *context, bool fast) { #if SANITIZER_WINDOWS - stack->Unwind(max_depth, pc, bp, context, 0, 0, fast); + stack->SlowUnwindStack(pc, max_depth); #else AsanThread *t; stack->size = 0; @@ -43,12 +43,14 @@ uptr stack_bottom = t->stack_bottom(); ScopedUnwinding unwind_scope(t); if (!SANITIZER_MIPS || IsValidFrame(bp, stack_top, stack_bottom)) { - stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, - fast); + if (StackTrace::WillUseFastUnwind(fast) && stack_top != 0) + stack->FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth); + else + stack->SlowUnwindStack(pc, max_depth); } } else if (!t && !fast) { /* If GetCurrentThread() has failed, try to do slow unwind anyways. */ - stack->Unwind(max_depth, pc, bp, context, 0, 0, false); + stack->SlowUnwindStack(pc, max_depth); } } #endif // SANITIZER_WINDOWS @@ -79,11 +81,6 @@ GetStackTrace(&stack, kStackTraceMax, pc, bp, 0, \ common_flags()->fast_unwind_on_fatal) -#define GET_STACK_TRACE_SIGNAL(sig) \ - BufferedStackTrace stack; \ - GetStackTrace(&stack, kStackTraceMax, (sig).pc, (sig).bp, (sig).context, \ - common_flags()->fast_unwind_on_fatal) - #define GET_STACK_TRACE_FATAL_HERE \ GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal) diff --git a/compiler-rt/lib/hwasan/hwasan.cc b/compiler-rt/lib/hwasan/hwasan.cc --- a/compiler-rt/lib/hwasan/hwasan.cc +++ b/compiler-rt/lib/hwasan/hwasan.cc @@ -155,10 +155,9 @@ if (!StackTrace::WillUseFastUnwind(request_fast_unwind)) { // Block reports from our interceptors during _Unwind_Backtrace. SymbolizerScope sym_scope; - return stack->Unwind(max_s, pc, bp, context, 0, 0, request_fast_unwind); + return stack->SlowUnwindStack(pc, context, max_s); } - stack->Unwind(max_s, pc, bp, context, t->stack_top(), t->stack_bottom(), - request_fast_unwind); + stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom(), max_s); } static void HWAsanCheckFailed(const char *file, int line, const char *cond, diff --git a/compiler-rt/lib/lsan/lsan.h b/compiler-rt/lib/lsan/lsan.h --- a/compiler-rt/lib/lsan/lsan.h +++ b/compiler-rt/lib/lsan/lsan.h @@ -55,7 +55,10 @@ stack_bottom = t->stack_begin(); } if (!SANITIZER_MIPS || IsValidFrame(bp, stack_top, stack_bottom)) { - stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, fast); + if (StackTrace::WillUseFastUnwind(fast) && stack_top != 0) + stack->FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth); + else + stack->SlowUnwindStack(pc, context, max_depth); } } diff --git a/compiler-rt/lib/msan/msan.cc b/compiler-rt/lib/msan/msan.cc --- a/compiler-rt/lib/msan/msan.cc +++ b/compiler-rt/lib/msan/msan.cc @@ -227,10 +227,9 @@ if (!t || !StackTrace::WillUseFastUnwind(request_fast_unwind)) { // Block reports from our interceptors during _Unwind_Backtrace. SymbolizerScope sym_scope; - return stack->Unwind(max_s, pc, bp, context, 0, 0, request_fast_unwind); + return stack->SlowUnwindStack(pc, max_s); } - stack->Unwind(max_s, pc, bp, context, t->stack_top(), t->stack_bottom(), - request_fast_unwind); + stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom(), max_s); } void PrintWarning(uptr pc, uptr bp) { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h @@ -56,9 +56,11 @@ void Print() const; static bool WillUseFastUnwind(bool request_fast_unwind) { + static_assert(SANITIZER_CAN_FAST_UNWIND || SANITIZER_CAN_SLOW_UNWIND, + "Neither fast nor slow unwinder is supported"); if (!SANITIZER_CAN_FAST_UNWIND) return false; - else if (!SANITIZER_CAN_SLOW_UNWIND) + if (!SANITIZER_CAN_SLOW_UNWIND) return true; return request_fast_unwind; } @@ -96,8 +98,19 @@ BufferedStackTrace() : StackTrace(trace_buffer, 0), top_frame_bp(0) {} void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0); - void Unwind(u32 max_depth, uptr pc, uptr bp, void *context, uptr stack_top, - uptr stack_bottom, bool request_fast_unwind); + + void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, + u32 max_depth); + void SlowUnwindStack(uptr pc, void *context, u32 max_depth) { + CHECK_GE(max_depth, 2); + if (context) + SlowUnwindStackWithContext(pc, context, max_depth); + else + SlowUnwindStack(pc, max_depth); + } + + void SlowUnwindStack(uptr pc, u32 max_depth); + void SlowUnwindStackWithContext(uptr pc, void *context, u32 max_depth); void Reset() { *static_cast(this) = StackTrace(trace_buffer, 0); @@ -105,11 +118,6 @@ } private: - void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, - u32 max_depth); - void SlowUnwindStack(uptr pc, u32 max_depth); - void SlowUnwindStackWithContext(uptr pc, void *context, - u32 max_depth); void PopStackFrames(uptr count); uptr LocatePcInTrace(uptr pc); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc @@ -40,6 +40,17 @@ top_frame_bp = 0; } +// TODO(yln): Remove and replace call sites with macro (#ifdef). +// Temporarily define symbols so we can link on all platforms/architectures. +#if !SANITIZER_CAN_SLOW_UNWIND +void BufferedStackTrace::SlowUnwindStack(uptr, u32) { + UNIMPLEMENTED(); +} +void BufferedStackTrace::SlowUnwindStackWithContext(uptr, void *, u32) { + UNIMPLEMENTED(); +} +#endif + // Sparc implemention is in its own file. #if !defined(__sparc__) @@ -49,7 +60,6 @@ static inline uhwptr *GetCanonicFrame(uptr bp, uptr stack_top, uptr stack_bottom) { - CHECK_GT(stack_top, stack_bottom); #ifdef __arm__ if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0; uhwptr *bp_prev = (uhwptr *)bp; @@ -70,8 +80,10 @@ void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, u32 max_depth) { - const uptr kPageSize = GetPageSizeCached(); + CHECK_NE(stack_bottom, 0); + CHECK_GT(stack_top, stack_bottom); CHECK_GE(max_depth, 2); + const uptr kPageSize = GetPageSizeCached(); trace_buffer[0] = pc; size = 1; if (stack_top < 4096) return; // Sanity check for stack top. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc @@ -54,34 +54,6 @@ Printf("DEDUP_TOKEN: %s\n", dedup_token.data()); } -void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context, - uptr stack_top, uptr stack_bottom, - bool request_fast_unwind) { - top_frame_bp = (max_depth > 0) ? bp : 0; - // Avoid doing any work for small max_depth. - if (max_depth == 0) { - size = 0; - return; - } - if (max_depth == 1) { - size = 1; - trace_buffer[0] = pc; - return; - } - if (!WillUseFastUnwind(request_fast_unwind)) { -#if SANITIZER_CAN_SLOW_UNWIND - if (context) - SlowUnwindStackWithContext(pc, context, max_depth); - else - SlowUnwindStack(pc, max_depth); -#else - UNREACHABLE("slow unwind requested but not available"); -#endif - } else { - FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth); - } -} - static int GetModuleAndOffsetForPc(uptr pc, char *module_name, uptr module_name_len, uptr *pc_offset) { const char *found_module_name = nullptr; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_sparc.cc b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_sparc.cc --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_sparc.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_sparc.cc @@ -23,8 +23,10 @@ void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, u32 max_depth) { - const uptr kPageSize = GetPageSizeCached(); + CHECK_NE(stack_bottom, 0); + CHECK_GT(stack_top, stack_bottom); CHECK_GE(max_depth, 2); + const uptr kPageSize = GetPageSizeCached(); trace_buffer[0] = pc; size = 1; if (stack_top < 4096) return; // Sanity check for stack top. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cc --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cc @@ -134,7 +134,8 @@ void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, u32 max_depth) { - CHECK_NE(context, nullptr); + CHECK(context); + CHECK_GE(max_depth, 2); UNREACHABLE("signal context doesn't exist"); } #endif // SANITIZER_CAN_SLOW_UNWIND diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cc --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cc @@ -103,9 +103,12 @@ GET_CALLER_PC_BP_SP; (void)sp; bool fast = common_flags()->fast_unwind_on_fatal; - if (fast) + if (StackTrace::WillUseFastUnwind(fast)) GetThreadStackTopAndBottom(false, &top, &bottom); - stack->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, fast); + if (StackTrace::WillUseFastUnwind(fast)) + stack->FastUnwindStack(pc, bp, top, bottom, kStackTraceMax); + else + stack->SlowUnwindStack(pc, kStackTraceMax); Printf("%s", d.Warning()); Report("WARNING: %s: writable-executable page usage\n", SanitizerToolName); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc --- a/compiler-rt/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc @@ -140,6 +140,7 @@ void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, u32 max_depth) { + CHECK(context); CHECK_GE(max_depth, 2); if (!unwind_backtrace_signal_arch) { SlowUnwindStack(pc, max_depth); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_unwind_win.cc b/compiler-rt/lib/sanitizer_common/sanitizer_unwind_win.cc --- a/compiler-rt/lib/sanitizer_common/sanitizer_unwind_win.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_unwind_win.cc @@ -41,6 +41,8 @@ void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, u32 max_depth) { + CHECK(context); + CHECK_GE(max_depth, 2); CONTEXT ctx = *(CONTEXT *)context; STACKFRAME64 stack_frame; memset(&stack_frame, 0, sizeof(stack_frame)); diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc @@ -23,8 +23,8 @@ 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); + trace.FastUnwindStack(start_pc, (uptr)&fake_stack[0], fake_top, + fake_bottom, max_depth); return true; } @@ -108,21 +108,6 @@ } } -TEST_F(FastUnwindTest, OneFrameStackTrace) { - if (!TryFastUnwind(1)) - return; - EXPECT_EQ(1U, trace.size); - EXPECT_EQ(start_pc, trace.trace[0]); - EXPECT_EQ((uhwptr)&fake_stack[0], trace.top_frame_bp); -} - -TEST_F(FastUnwindTest, ZeroFramesStackTrace) { - if (!TryFastUnwind(0)) - return; - EXPECT_EQ(0U, trace.size); - EXPECT_EQ(0U, trace.top_frame_bp); -} - TEST_F(FastUnwindTest, FPBelowPrevFP) { // The next FP points to unreadable memory inside the stack limits, but below // current FP. @@ -148,19 +133,4 @@ } } -TEST(SlowUnwindTest, ShortStackTrace) { - if (StackTrace::WillUseFastUnwind(false)) - return; - BufferedStackTrace stack; - uptr pc = StackTrace::GetCurrentPc(); - uptr bp = GET_CURRENT_FRAME(); - stack.Unwind(0, pc, bp, 0, 0, 0, false); - EXPECT_EQ(0U, stack.size); - EXPECT_EQ(0U, stack.top_frame_bp); - stack.Unwind(1, pc, bp, 0, 0, 0, false); - EXPECT_EQ(1U, stack.size); - EXPECT_EQ(pc, stack.trace[0]); - EXPECT_EQ(bp, stack.top_frame_bp); -} - } // namespace __sanitizer diff --git a/compiler-rt/lib/tsan/dd/dd_rtl.cc b/compiler-rt/lib/tsan/dd/dd_rtl.cc --- a/compiler-rt/lib/tsan/dd/dd_rtl.cc +++ b/compiler-rt/lib/tsan/dd/dd_rtl.cc @@ -21,7 +21,7 @@ static u32 CurrentStackTrace(Thread *thr, uptr skip) { BufferedStackTrace stack; thr->ignore_interceptors = true; - stack.Unwind(1000, 0, 0, 0, 0, 0, false); + stack.SlowUnwindStack(0, 1000); thr->ignore_interceptors = false; if (stack.size <= skip) return 0; diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl.cc --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cc @@ -331,8 +331,12 @@ uptr top = 0; uptr bottom = 0; bool fast = common_flags()->fast_unwind_on_fatal; - if (fast) GetThreadStackTopAndBottom(false, &top, &bottom); - stack->Unwind(kStackTraceMax, sig.pc, sig.bp, sig.context, top, bottom, fast); + if (StackTrace::WillUseFastUnwind(fast)) + GetThreadStackTopAndBottom(false, &top, &bottom); + if (StackTrace::WillUseFastUnwind(fast)) + stack->FastUnwindStack(sig.pc, sig.bp, top, bottom, kStackTraceMax); + else + stack->SlowUnwindStack(sig.pc, sig.context, kStackTraceMax); } static void TsanOnDeadlySignal(int signo, void *siginfo, void *context) { diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc @@ -739,7 +739,10 @@ BufferedStackTrace *ptrace = new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace))) BufferedStackTrace(); - ptrace->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, false); + if (StackTrace::WillUseFastUnwind(false)) + ptrace->FastUnwindStack(pc, bp, top, bottom, kStackTraceMax); + else + ptrace->SlowUnwindStack(pc, kStackTraceMax); 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]; diff --git a/compiler-rt/lib/ubsan/ubsan_diag.cc b/compiler-rt/lib/ubsan/ubsan_diag.cc --- a/compiler-rt/lib/ubsan/ubsan_diag.cc +++ b/compiler-rt/lib/ubsan/ubsan_diag.cc @@ -30,9 +30,12 @@ uptr bp, void *context, bool fast) { uptr top = 0; uptr bottom = 0; - if (fast) + if (StackTrace::WillUseFastUnwind(fast)) GetThreadStackTopAndBottom(false, &top, &bottom); - stack->Unwind(max_depth, pc, bp, context, top, bottom, fast); + if (StackTrace::WillUseFastUnwind(fast)) + stack->FastUnwindStack(pc, bp, top, bottom, max_depth); + else + stack->SlowUnwindStack(pc, context, max_depth); } static void MaybePrintStackTrace(uptr pc, uptr bp) { diff --git a/compiler-rt/lib/ubsan/ubsan_diag_standalone.cc b/compiler-rt/lib/ubsan/ubsan_diag_standalone.cc --- a/compiler-rt/lib/ubsan/ubsan_diag_standalone.cc +++ b/compiler-rt/lib/ubsan/ubsan_diag_standalone.cc @@ -22,14 +22,16 @@ uptr top = 0; uptr bottom = 0; bool request_fast_unwind = common_flags()->fast_unwind_on_fatal; - if (__sanitizer::StackTrace::WillUseFastUnwind(request_fast_unwind)) - __sanitizer::GetThreadStackTopAndBottom(false, &top, &bottom); + if (StackTrace::WillUseFastUnwind(request_fast_unwind)) + GetThreadStackTopAndBottom(false, &top, &bottom); GET_CURRENT_PC_BP_SP; (void)sp; BufferedStackTrace stack; - stack.Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, - request_fast_unwind); + if (StackTrace::WillUseFastUnwind(request_fast_unwind)) + stack.FastUnwindStack(pc, bp, top, bottom, kStackTraceMax); + else + stack.SlowUnwindStack(pc, kStackTraceMax); stack.Print(); } } // extern "C" diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc b/compiler-rt/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc --- a/compiler-rt/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc +++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc @@ -10,8 +10,8 @@ // XFAIL: netbsd && !asan -// FIXME(dliew): Make this test work with other sanitizers -// XFAIL: darwin && (tsan || ubsan) +// FIXME(dliew): Make this test work with TSan +// XFAIL: darwin && tsan volatile int *null = 0;