tsan: increase max shadow stack size + reduce memory consumption at the same time (by not memorizing full stacks in traces)


git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@163322 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/tsan/rtl/tsan_defs.h b/lib/tsan/rtl/tsan_defs.h
index f796de7..652d959 100644
--- a/lib/tsan/rtl/tsan_defs.h
+++ b/lib/tsan/rtl/tsan_defs.h
@@ -29,7 +29,8 @@
 const unsigned kMaxTidInClock = kMaxTid * 2;  // This includes msb 'freed' bit.
 const int kClkBits = 43;
 #ifndef TSAN_GO
-const int kShadowStackSize = 1024;
+const int kShadowStackSize = 4*1024;
+const int kTraceStackSize = 256;
 #endif
 
 #ifdef TSAN_SHADOW_COUNT
diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc
index 869900b..a284a96 100644
--- a/lib/tsan/rtl/tsan_report.cc
+++ b/lib/tsan/rtl/tsan_report.cc
@@ -146,7 +146,7 @@
 
 #else
 
-static void PrintStack(const ReportStack *ent) {
+void PrintStack(const ReportStack *ent) {
   for (int i = 0; ent; ent = ent->next, i++) {
     TsanPrintf("  %s()\n      %s:%d +0x%zx\n",
         ent->func, ent->file, ent->line, (void*)ent->offset);
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index 6ca8ca7..3ea5384 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -230,6 +230,7 @@
   return failed ? flags()->exitcode : 0;
 }
 
+#ifndef TSAN_GO
 u32 CurrentStackId(ThreadState *thr, uptr pc) {
   if (thr->shadow_stack_pos == 0)  // May happen during bootstrap.
     return 0;
@@ -243,6 +244,7 @@
     thr->shadow_stack_pos--;
   return id;
 }
+#endif
 
 void TraceSwitch(ThreadState *thr) {
   thr->nomalloc++;
diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc
index f2f5b1c..3efe452 100644
--- a/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/lib/tsan/rtl/tsan_rtl_report.cc
@@ -85,9 +85,9 @@
   } else if (last || last2) {
     // Ensure that we recovered stack completely. Trimmed stack
     // can actually happen if we do not instrument some code,
-    // so it's only a DCHECK. However we must try hard to not miss it
+    // so it's only a debug print. However we must try hard to not miss it
     // due to our fault.
-    TsanPrintf("Bottom stack frame of stack %zx is missed\n", stack->pc);
+    DPrintf("Bottom stack frame of stack %zx is missed\n", stack->pc);
   }
 #else
   if (last && 0 == internal_strcmp(last, "schedunlock"))
@@ -163,6 +163,7 @@
   rt->stack = SymbolizeStack(tctx->creation_stack);
 }
 
+#ifndef TSAN_GO
 static ThreadContext *FindThread(int unique_id) {
   CTX()->thread_mtx.CheckLocked();
   for (unsigned i = 0; i < kMaxTid; i++) {
@@ -173,6 +174,7 @@
   }
   return 0;
 }
+#endif
 
 void ScopedReport::AddMutex(const SyncVar *s) {
   void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex));
@@ -230,6 +232,7 @@
   }
 }
 
+#ifndef TSAN_GO
 void ScopedReport::AddSleep(u32 stack_id) {
   uptr ssz = 0;
   const uptr *stack = StackDepotGet(stack_id, &ssz);
@@ -239,6 +242,7 @@
     rep_->sleep = SymbolizeStack(trace);
   }
 }
+#endif
 
 const ReportDesc *ScopedReport::GetReport() const {
   return rep_;
@@ -285,8 +289,6 @@
     } else if (typ == EventTypeFuncEnter) {
       stack[pos++] = pc;
     } else if (typ == EventTypeFuncExit) {
-      // Since we have full stacks, this should never happen.
-      DCHECK_GT(pos, 0);
       if (pos > 0)
         pos--;
     }
diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc
index 86265bb..642d1b2 100644
--- a/lib/tsan/rtl/tsan_sync.cc
+++ b/lib/tsan/rtl/tsan_sync.cc
@@ -236,15 +236,19 @@
   n_ = thr->shadow_stack_pos - thr->shadow_stack;
   if (n_ + !!toppc == 0)
     return;
+  uptr start = 0;
   if (c_) {
     CHECK_NE(s_, 0);
-    CHECK_LE(n_ + !!toppc, c_);
+    if (n_ + !!toppc > c_) {
+      start = n_ - c_ + !!toppc;
+      n_ = c_ - !!toppc;
+    }
   } else {
     s_ = (uptr*)internal_alloc(MBlockStackTrace,
                                (n_ + !!toppc) * sizeof(s_[0]));
   }
   for (uptr i = 0; i < n_; i++)
-    s_[i] = thr->shadow_stack[i];
+    s_[i] = thr->shadow_stack[start + i];
   if (toppc) {
     s_[n_] = toppc;
     n_++;
diff --git a/lib/tsan/rtl/tsan_trace.h b/lib/tsan/rtl/tsan_trace.h
index 97ec969..fd5c673 100644
--- a/lib/tsan/rtl/tsan_trace.h
+++ b/lib/tsan/rtl/tsan_trace.h
@@ -47,12 +47,12 @@
   StackTrace stack0;  // Start stack for the trace.
   u64        epoch0;  // Start epoch for the trace.
 #ifndef TSAN_GO
-  uptr       stack0buf[kShadowStackSize];
+  uptr       stack0buf[kTraceStackSize];
 #endif
 
   TraceHeader()
 #ifndef TSAN_GO
-      : stack0(stack0buf, kShadowStackSize)
+      : stack0(stack0buf, kTraceStackSize)
 #else
       : stack0()
 #endif
diff --git a/lib/tsan/unit_tests/tsan_stack_test.cc b/lib/tsan/unit_tests/tsan_stack_test.cc
new file mode 100644
index 0000000..d539295
--- /dev/null
+++ b/lib/tsan/unit_tests/tsan_stack_test.cc
@@ -0,0 +1,80 @@
+//===-- tsan_stack_test.cc ------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_sync.h"
+#include "tsan_rtl.h"
+#include "gtest/gtest.h"
+#include <string.h>
+
+namespace __tsan {
+
+static void TestStackTrace(StackTrace *trace) {
+  ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0);
+
+  trace->ObtainCurrent(&thr, 0);
+  EXPECT_EQ(trace->Size(), (uptr)0);
+
+  trace->ObtainCurrent(&thr, 42);
+  EXPECT_EQ(trace->Size(), (uptr)1);
+  EXPECT_EQ(trace->Get(0), (uptr)42);
+
+  *thr.shadow_stack_pos++ = 100;
+  *thr.shadow_stack_pos++ = 101;
+  trace->ObtainCurrent(&thr, 0);
+  EXPECT_EQ(trace->Size(), (uptr)2);
+  EXPECT_EQ(trace->Get(0), (uptr)100);
+  EXPECT_EQ(trace->Get(1), (uptr)101);
+
+  trace->ObtainCurrent(&thr, 42);
+  EXPECT_EQ(trace->Size(), (uptr)3);
+  EXPECT_EQ(trace->Get(0), (uptr)100);
+  EXPECT_EQ(trace->Get(1), (uptr)101);
+  EXPECT_EQ(trace->Get(2), (uptr)42);
+}
+
+TEST(StackTrace, Basic) {
+  ScopedInRtl in_rtl;
+  StackTrace trace;
+  TestStackTrace(&trace);
+}
+
+TEST(StackTrace, StaticBasic) {
+  ScopedInRtl in_rtl;
+  uptr buf[10];
+  StackTrace trace1(buf, 10);
+  TestStackTrace(&trace1);
+  StackTrace trace2(buf, 3);
+  TestStackTrace(&trace2);
+}
+
+TEST(StackTrace, StaticTrim) {
+  ScopedInRtl in_rtl;
+  uptr buf[2];
+  StackTrace trace(buf, 2);
+  ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0);
+
+  *thr.shadow_stack_pos++ = 100;
+  *thr.shadow_stack_pos++ = 101;
+  *thr.shadow_stack_pos++ = 102;
+  trace.ObtainCurrent(&thr, 0);
+  EXPECT_EQ(trace.Size(), (uptr)2);
+  EXPECT_EQ(trace.Get(0), (uptr)101);
+  EXPECT_EQ(trace.Get(1), (uptr)102);
+
+  trace.ObtainCurrent(&thr, 42);
+  EXPECT_EQ(trace.Size(), (uptr)2);
+  EXPECT_EQ(trace.Get(0), (uptr)102);
+  EXPECT_EQ(trace.Get(1), (uptr)42);
+}
+
+
+}  // namespace __tsan