[NFC][Sanitizer] Add new BufferedStackTrace::Unwind API
authorJulian Lettner <jlettner@apple.com>
Fri, 1 Mar 2019 04:03:38 +0000 (04:03 +0000)
committerJulian Lettner <jlettner@apple.com>
Fri, 1 Mar 2019 04:03:38 +0000 (04:03 +0000)
Retrying without replacing call sites in sanitizer_common (which might
not have a symbol definition).

Add new Unwind API. This is the final envisioned API with the correct
abstraction level. It hides/slow fast unwinder selection from the caller
and doesn't take any arguments that would leak that abstraction (i.e.,
arguments like stack_top/stack_bottom).

GetStackTrace will become an implementation detail (private method) of
the BufferedStackTrace class.

Reviewers: vitalybuka

Differential Revision: https://reviews.llvm.org/D58741

> llvm-svn: 355168

llvm-svn: 355172

12 files changed:
compiler-rt/lib/asan/asan_errors.cc
compiler-rt/lib/asan/asan_stack.h
compiler-rt/lib/hwasan/hwasan.h
compiler-rt/lib/hwasan/hwasan_linux.cpp
compiler-rt/lib/lsan/lsan.cc
compiler-rt/lib/lsan/lsan.h
compiler-rt/lib/msan/msan.cc
compiler-rt/lib/msan/msan.h
compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
compiler-rt/lib/tsan/rtl/tsan_rtl.cc
compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
compiler-rt/lib/ubsan/ubsan_diag_standalone.cc

index 6fd465d..16a3009 100644 (file)
@@ -35,7 +35,7 @@ static void OnStackUnwind(const SignalContext &sig,
   // corresponding code in the sanitizer_common and we use this callback to
   // print it.
   static_cast<const ScarinessScoreBase *>(callback_context)->Print();
-  GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, sig.context, fast);
+  stack->Unwind(sig.pc, sig.bp, sig.context, fast);
 }
 
 void ErrorDeadlySignal::Print() {
index 3480d91..3a4b3ce 100644 (file)
@@ -42,19 +42,19 @@ u32 GetMallocContextSize();
       if (max_size > 1) stack.trace_buffer[1] = GET_CALLER_PC(); \
     }                                                            \
   } else {                                                       \
-    GetStackTrace(&stack, max_size, StackTrace::GetCurrentPc(),  \
-                  GET_CURRENT_FRAME(), 0, fast);                 \
+    stack.Unwind(StackTrace::GetCurrentPc(),                     \
+                 GET_CURRENT_FRAME(), nullptr, fast, max_size);  \
   }
 
 #define GET_STACK_TRACE_FATAL(pc, bp)              \
   BufferedStackTrace stack;                        \
-  GetStackTrace(&stack, kStackTraceMax, pc, bp, 0, \
-                common_flags()->fast_unwind_on_fatal)
+  stack.Unwind(pc, bp, nullptr,                    \
+               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)
+  stack.Unwind((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)
index b7357e9..74eaa0c 100644 (file)
@@ -112,16 +112,15 @@ const int STACK_TRACE_TAG_POISON = StackTrace::TAG_CUSTOM + 1;
 
 #define GET_MALLOC_STACK_TRACE                                            \
   BufferedStackTrace stack;                                               \
-  if (hwasan_inited)                                                       \
-  GetStackTrace(&stack, common_flags()->malloc_context_size,              \
-                StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), nullptr, \
-                common_flags()->fast_unwind_on_malloc)
+  if (hwasan_inited)                                                      \
+    stack.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(),         \
+                 nullptr, common_flags()->fast_unwind_on_malloc,          \
+                 common_flags()->malloc_context_size)
 
 #define GET_FATAL_STACK_TRACE_PC_BP(pc, bp)              \
   BufferedStackTrace stack;                              \
-  if (hwasan_inited)                                       \
-  GetStackTrace(&stack, kStackTraceMax, pc, bp, nullptr, \
-                common_flags()->fast_unwind_on_fatal)
+  if (hwasan_inited)                                     \
+    stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal)
 
 #define GET_FATAL_STACK_TRACE_HERE \
   GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
index 4ab7c32..ce0c55f 100644 (file)
@@ -378,8 +378,7 @@ static void HandleTagMismatch(AccessInfo ai, uptr pc, uptr frame,
   InternalMmapVector<BufferedStackTrace> stack_buffer(1);
   BufferedStackTrace *stack = stack_buffer.data();
   stack->Reset();
-  GetStackTrace(stack, kStackTraceMax, pc, frame, uc,
-                common_flags()->fast_unwind_on_fatal);
+  stack->Unwind(pc, frame, uc, common_flags()->fast_unwind_on_fatal);
 
   bool fatal = flags()->halt_on_error || !ai.recover;
   ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store, fatal);
@@ -417,8 +416,8 @@ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __hwasan_tag_mismatch(
 
 static void OnStackUnwind(const SignalContext &sig, const void *,
                           BufferedStackTrace *stack) {
-  GetStackTrace(stack, kStackTraceMax, StackTrace::GetNextInstructionPc(sig.pc),
-                sig.bp, sig.context, common_flags()->fast_unwind_on_fatal);
+  stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context,
+                common_flags()->fast_unwind_on_fatal);
 }
 
 void HwasanOnDeadlySignal(int signo, void *info, void *context) {
index cf8d526..5ff7347 100644 (file)
@@ -89,7 +89,7 @@ static void InitializeFlags() {
 
 static void OnStackUnwind(const SignalContext &sig, const void *,
                           BufferedStackTrace *stack) {
-  GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, sig.context,
+  stack->Unwind(sig.pc, sig.bp, sig.context,
                 common_flags()->fast_unwind_on_fatal);
 }
 
index 049fba2..9904ada 100644 (file)
@@ -17,8 +17,8 @@
 
 #define GET_STACK_TRACE(max_size, fast)                       \
   __sanitizer::BufferedStackTrace stack;                      \
-  GetStackTrace(&stack, max_size, StackTrace::GetCurrentPc(), \
-                GET_CURRENT_FRAME(), nullptr, fast);
+  stack.Unwind(StackTrace::GetCurrentPc(),                    \
+               GET_CURRENT_FRAME(), nullptr, fast, max_size);
 
 #define GET_STACK_TRACE_FATAL \
   GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
index 29d58c0..1ecbcd4 100644 (file)
@@ -382,7 +382,7 @@ void __msan_warning_noreturn() {
 
 static void OnStackUnwind(const SignalContext &sig, const void *,
                           BufferedStackTrace *stack) {
-  GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, sig.context,
+  stack->Unwind(sig.pc, sig.bp, sig.context,
                 common_flags()->fast_unwind_on_fatal);
 }
 
index 6d17f50..2112568 100644 (file)
@@ -325,23 +325,21 @@ const int STACK_TRACE_TAG_POISON = StackTrace::TAG_CUSTOM + 1;
 #define GET_MALLOC_STACK_TRACE                                            \
   BufferedStackTrace stack;                                               \
   if (__msan_get_track_origins() && msan_inited)                          \
-  GetStackTrace(&stack, common_flags()->malloc_context_size,              \
-                StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), nullptr, \
-                common_flags()->fast_unwind_on_malloc)
+    stack.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(),         \
+                 nullptr, common_flags()->fast_unwind_on_malloc,          \
+                 common_flags()->malloc_context_size)
 
 // For platforms which support slow unwinder only, we restrict the store context
 // size to 1, basically only storing the current pc. We do this because the slow
 // unwinder which is based on libunwind is not async signal safe and causes
 // random freezes in forking applications as well as in signal handlers.
-#define GET_STORE_STACK_TRACE_PC_BP(pc, bp)                               \
-  BufferedStackTrace stack;                                               \
-  if (__msan_get_track_origins() > 1 && msan_inited) {                    \
-    if (!SANITIZER_CAN_FAST_UNWIND)                                       \
-      GetStackTrace(&stack, Min(1, flags()->store_context_size), pc, bp,  \
-                    nullptr, false);                                      \
-    else                                                                  \
-      GetStackTrace(&stack, flags()->store_context_size, pc, bp, nullptr, \
-                    common_flags()->fast_unwind_on_malloc);               \
+#define GET_STORE_STACK_TRACE_PC_BP(pc, bp)                                    \
+  BufferedStackTrace stack;                                                    \
+  if (__msan_get_track_origins() > 1 && msan_inited) {                         \
+    int size = flags()->store_context_size;                                    \
+    if (!SANITIZER_CAN_FAST_UNWIND)                                            \
+      size = Min(size, 1);                                                     \
+    stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_malloc, size);\
   }
 
 #define GET_STORE_STACK_TRACE \
@@ -350,8 +348,7 @@ const int STACK_TRACE_TAG_POISON = StackTrace::TAG_CUSTOM + 1;
 #define GET_FATAL_STACK_TRACE_PC_BP(pc, bp)              \
   BufferedStackTrace stack;                              \
   if (msan_inited)                                       \
-  GetStackTrace(&stack, kStackTraceMax, pc, bp, nullptr, \
-                common_flags()->fast_unwind_on_fatal)
+    stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal)
 
 #define GET_FATAL_STACK_TRACE_HERE \
   GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
index eeed983..b62d213 100644 (file)
 
 namespace __sanitizer {
 
+struct BufferedStackTrace;
+// Get the stack trace with the given pc and bp.
+// The pc will be in the position 0 of the resulting stack trace.
+// The bp may refer to the current frame or to the caller's frame.
+void GetStackTrace(BufferedStackTrace *stack, uptr max_depth, uptr pc, uptr bp,
+                   void *context, bool request_fast_unwind);
+
 static const u32 kStackTraceMax = 256;
 
 #if defined(__sparc__) || (SANITIZER_LINUX && defined(__mips__))
@@ -96,6 +103,20 @@ struct BufferedStackTrace : public StackTrace {
   BufferedStackTrace() : StackTrace(trace_buffer, 0), top_frame_bp(0) {}
 
   void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0);
+
+  void Unwind(uptr pc, uptr bp, void *context, bool request_fast,
+              u32 max_depth = kStackTraceMax) {
+    top_frame_bp = (max_depth > 0) ? bp : 0;
+    // Small max_depth optimization
+    if (max_depth <= 1) {
+      if (max_depth == 1)
+        trace_buffer[0] = pc;
+      size = max_depth;
+      return;
+    }
+    GetStackTrace(this, max_depth, pc, bp, context, request_fast);
+  }
+
   void Unwind(u32 max_depth, uptr pc, uptr bp, void *context, uptr stack_top,
               uptr stack_bottom, bool request_fast_unwind);
 
@@ -121,31 +142,27 @@ static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) {
   return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr);
 }
 
-// Get the stack trace with the given pc and bp.
-// The pc will be in the position 0 of the resulting stack trace.
-// The bp may refer to the current frame or to the caller's frame.
-void GetStackTrace(BufferedStackTrace *stack, uptr max_depth, uptr pc, uptr bp,
-                   void *context, bool request_fast_unwind);
-
 }  // namespace __sanitizer
 
 // Use this macro if you want to print stack trace with the caller
 // of the current function in the top frame.
-#define GET_CALLER_PC_BP_SP \
-  uptr bp = GET_CURRENT_FRAME();              \
-  uptr pc = GET_CALLER_PC();                  \
-  uptr local_stack;                           \
-  uptr sp = (uptr)&local_stack
-
 #define GET_CALLER_PC_BP \
   uptr bp = GET_CURRENT_FRAME();              \
   uptr pc = GET_CALLER_PC();
 
+#define GET_CALLER_PC_BP_SP \
+  GET_CALLER_PC_BP;                           \
+  uptr local_stack;                           \
+  uptr sp = (uptr)&local_stack
+
 // Use this macro if you want to print stack trace with the current
 // function in the top frame.
-#define GET_CURRENT_PC_BP_SP \
+#define GET_CURRENT_PC_BP \
   uptr bp = GET_CURRENT_FRAME();              \
-  uptr pc = StackTrace::GetCurrentPc();   \
+  uptr pc = StackTrace::GetCurrentPc()
+
+#define GET_CURRENT_PC_BP_SP \
+  GET_CURRENT_PC_BP;                          \
   uptr local_stack;                           \
   uptr sp = (uptr)&local_stack
 
index 0b690b7..3d23f50 100644 (file)
@@ -328,14 +328,8 @@ static void CheckShadowMapping() {
 #if !SANITIZER_GO
 static void OnStackUnwind(const SignalContext &sig, const void *,
                           BufferedStackTrace *stack) {
-  uptr top = 0;
-  uptr bottom = 0;
-  bool fast = common_flags()->fast_unwind_on_fatal;
-  if (StackTrace::WillUseFastUnwind(fast)) {
-    GetThreadStackTopAndBottom(false, &top, &bottom);
-    stack->Unwind(kStackTraceMax, sig.pc, sig.bp, nullptr, top, bottom, true);
-  } else
-    stack->Unwind(kStackTraceMax, sig.pc, 0, sig.context, 0, 0, false);
+  stack->Unwind(sig.pc, sig.bp, sig.context,
+                common_flags()->fast_unwind_on_fatal);
 }
 
 static void TsanOnDeadlySignal(int signo, void *siginfo, void *context) {
index 77fbcb0..220a425 100644 (file)
@@ -729,18 +729,12 @@ void PrintCurrentStack(ThreadState *thr, uptr pc) {
 ALWAYS_INLINE
 void PrintCurrentStackSlow(uptr pc) {
 #if !SANITIZER_GO
-  uptr bp = 0;
-  uptr top = 0;
-  uptr bottom = 0;
+  uptr bp = GET_CURRENT_FRAME();
   BufferedStackTrace *ptrace =
       new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace)))
           BufferedStackTrace();
-  if (__sanitizer::StackTrace::WillUseFastUnwind(false)) {
-    bp = GET_CURRENT_FRAME();
-    __sanitizer::GetThreadStackTopAndBottom(false, &top, &bottom);
-    ptrace->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, true);
-  } else
-    ptrace->Unwind(kStackTraceMax, pc, 0, nullptr, 0, 0, false);
+  ptrace->Unwind(pc, bp, nullptr, 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];
index 1eff090..d2b7d6e 100644 (file)
 
 using namespace __ubsan;
 
+void __sanitizer::GetStackTrace(BufferedStackTrace *stack, uptr max_depth,
+                                uptr pc, uptr bp, void *context, bool fast) {
+  uptr top = 0;
+  uptr bottom = 0;
+  if (StackTrace::WillUseFastUnwind(fast)) {
+    GetThreadStackTopAndBottom(false, &top, &bottom);
+    stack->Unwind(max_depth, pc, bp, nullptr, top, bottom, true);
+  } else
+    stack->Unwind(max_depth, pc, bp, context, 0, 0, false);
+}
+
 extern "C" {
 SANITIZER_INTERFACE_ATTRIBUTE
 void __sanitizer_print_stack_trace() {
-  uptr top = 0;
-  uptr bottom = 0;
-  bool request_fast_unwind = common_flags()->fast_unwind_on_fatal;
-  GET_CURRENT_PC_BP_SP;
-  (void)sp;
+  GET_CURRENT_PC_BP;
   BufferedStackTrace stack;
-  if (__sanitizer::StackTrace::WillUseFastUnwind(request_fast_unwind)) {
-    __sanitizer::GetThreadStackTopAndBottom(false, &top, &bottom);
-    stack.Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, true);
-  } else {
-    stack.Unwind(kStackTraceMax, pc, 0, nullptr, 0, 0, false);
-  }
+  stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal);
   stack.Print();
 }
 } // extern "C"