[compiler-rt] r192797 - tsan: move shadow stack from thread descriptors to fixed addresses

Dmitry Vyukov dvyukov at google.com
Wed Oct 16 08:35:13 PDT 2013


Author: dvyukov
Date: Wed Oct 16 10:35:12 2013
New Revision: 192797

URL: http://llvm.org/viewvc/llvm-project?rev=192797&view=rev
Log:
tsan: move shadow stack from thread descriptors to fixed addresses

This allows to increase max shadow stack size to 64K,
and reliably catch shadow stack overflows instead of silently
corrupting memory.


Added:
    compiler-rt/trunk/lib/tsan/lit_tests/deep_stack0.cc
    compiler-rt/trunk/lib/tsan/lit_tests/deep_stack1.cc
Modified:
    compiler-rt/trunk/lib/tsan/lit_tests/global_race.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_trace.h
    compiler-rt/trunk/lib/tsan/tests/unit/tsan_stack_test.cc

Added: compiler-rt/trunk/lib/tsan/lit_tests/deep_stack0.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/deep_stack0.cc?rev=192797&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/deep_stack0.cc (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/deep_stack0.cc Wed Oct 16 10:35:12 2013
@@ -0,0 +1,38 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+volatile int X;
+volatile int N;
+void (*volatile F)();
+
+static void foo() {
+  if (--N == 0)
+    X = 42;
+  else
+    F();
+}
+
+void *Thread(void *p) {
+  sleep(1);
+  F();
+  return 0;
+}
+
+int main() {
+  N = 50000;
+  F = foo;
+  pthread_t t;
+  pthread_attr_t a;
+  pthread_attr_init(&a);
+  pthread_attr_setstacksize(&a, N * 256 + (1 << 20));
+  pthread_create(&t, &a, Thread, 0);
+  X = 43;
+  pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK:    #100 foo
+// We must output suffucuently large stack (at least 100 frames)
+

Added: compiler-rt/trunk/lib/tsan/lit_tests/deep_stack1.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/deep_stack1.cc?rev=192797&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/deep_stack1.cc (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/deep_stack1.cc Wed Oct 16 10:35:12 2013
@@ -0,0 +1,38 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+volatile int X;
+volatile int N;
+void (*volatile F)();
+
+static void foo() {
+  if (--N == 0)
+    X = 42;
+  else
+    F();
+}
+
+void *Thread(void *p) {
+  F();
+  return 0;
+}
+
+int main() {
+  N = 50000;
+  F = foo;
+  pthread_t t;
+  pthread_attr_t a;
+  pthread_attr_init(&a);
+  pthread_attr_setstacksize(&a, N * 256 + (1 << 20));
+  pthread_create(&t, &a, Thread, 0);
+  sleep(1);
+  X = 43;
+  pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK:    #100 foo
+// We must output suffucuently large stack (at least 100 frames)
+

Modified: compiler-rt/trunk/lib/tsan/lit_tests/global_race.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/global_race.cc?rev=192797&r1=192796&r2=192797&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/global_race.cc (original)
+++ compiler-rt/trunk/lib/tsan/lit_tests/global_race.cc Wed Oct 16 10:35:12 2013
@@ -4,7 +4,7 @@
 #include <stddef.h>
 
 int GlobalData[10];
-int y;
+int qwerty;
 namespace XXX {
   struct YYY {
     static int ZZZ[10];
@@ -14,19 +14,19 @@ namespace XXX {
 
 void *Thread(void *a) {
   GlobalData[2] = 42;
-  y = 1;
+  qwerty = 1;
   XXX::YYY::ZZZ[0] = 1;
   return 0;
 }
 
 int main() {
   fprintf(stderr, "addr=%p\n", GlobalData);
-  fprintf(stderr, "addr2=%p\n", &y);
+  fprintf(stderr, "addr2=%p\n", &qwerty);
   fprintf(stderr, "addr3=%p\n", XXX::YYY::ZZZ);
   pthread_t t;
   pthread_create(&t, 0, Thread, 0);
   GlobalData[2] = 43;
-  y = 0;
+  qwerty = 0;
   XXX::YYY::ZZZ[0] = 0;
   pthread_join(t, 0);
 }
@@ -37,6 +37,6 @@ int main() {
 // CHECK: WARNING: ThreadSanitizer: data race
 // CHECK: Location is global 'GlobalData' of size 40 at [[ADDR]] ({{.*}}+0x{{[0-9,a-f]+}})
 // CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Location is global 'y' of size 4 at [[ADDR2]] ({{.*}}+0x{{[0-9,a-f]+}})
+// CHECK: Location is global 'qwerty' of size 4 at [[ADDR2]] ({{.*}}+0x{{[0-9,a-f]+}})
 // CHECK: WARNING: ThreadSanitizer: data race
 // CHECK: Location is global 'XXX::YYY::ZZZ' of size 40 at [[ADDR3]] ({{.*}}+0x{{[0-9,a-f]+}})

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h?rev=192797&r1=192796&r2=192797&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h Wed Oct 16 10:35:12 2013
@@ -41,10 +41,8 @@ const int kTidBits = 13;
 const unsigned kMaxTid = 1 << kTidBits;
 const unsigned kMaxTidInClock = kMaxTid * 2;  // This includes msb 'freed' bit.
 const int kClkBits = 42;
-#ifndef TSAN_GO
-const int kShadowStackSize = 4 * 1024;
-const int kTraceStackSize = 256;
-#endif
+const uptr kShadowStackSize = 64 * 1024;
+const uptr kTraceStackSize = 256;
 
 #ifdef TSAN_SHADOW_COUNT
 # if TSAN_SHADOW_COUNT == 2 \

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h?rev=192797&r1=192796&r2=192797&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h Wed Oct 16 10:35:12 2013
@@ -138,14 +138,20 @@ uptr GetRSS();
 
 const char *InitializePlatform();
 void FinalizePlatform();
+
+// The additional page is to catch shadow stack overflow as paging fault.
+const uptr kTotalTraceSize = (kTraceSize * sizeof(Event) + sizeof(Trace) + 4096
+    + 4095) & ~4095;
+
 uptr ALWAYS_INLINE GetThreadTrace(int tid) {
-  uptr p = kTraceMemBegin + (uptr)(tid * 2) * kTraceSize * sizeof(Event);
+  uptr p = kTraceMemBegin + (uptr)tid * kTotalTraceSize;
   DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
   return p;
 }
 
 uptr ALWAYS_INLINE GetThreadTraceHeader(int tid) {
-  uptr p = kTraceMemBegin + (uptr)(tid * 2 + 1) * kTraceSize * sizeof(Event);
+  uptr p = kTraceMemBegin + (uptr)tid * kTotalTraceSize
+      + kTraceSize * sizeof(Event);
   DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
   return p;
 }

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc?rev=192797&r1=192796&r2=192797&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc Wed Oct 16 10:35:12 2013
@@ -90,7 +90,6 @@ ThreadState::ThreadState(Context *ctx, i
   // they may be accessed before the ctor.
   // , ignore_reads_and_writes()
   // , in_rtl()
-  , shadow_stack_pos(&shadow_stack[0])
 #ifndef TSAN_GO
   , jmp_bufs(MBlockJmpBuf)
 #endif
@@ -201,8 +200,10 @@ void MapThreadTrace(uptr addr, uptr size
   DPrintf("#0: Mapping trace at %p-%p(0x%zx)\n", addr, addr + size, size);
   CHECK_GE(addr, kTraceMemBegin);
   CHECK_LE(addr + size, kTraceMemBegin + kTraceMemSize);
-  if (addr != (uptr)MmapFixedNoReserve(addr, size)) {
-    Printf("FATAL: ThreadSanitizer can not mmap thread trace\n");
+  uptr addr1 = (uptr)MmapFixedNoReserve(addr, size);
+  if (addr1 != addr) {
+    Printf("FATAL: ThreadSanitizer can not mmap thread trace (%p/%p->%p)\n",
+        addr, size, addr1);
     Die();
   }
 }
@@ -660,9 +661,9 @@ void FuncEntry(ThreadState *thr, uptr pc
 
   // Shadow stack maintenance can be replaced with
   // stack unwinding during trace switch (which presumably must be faster).
-  DCHECK_GE(thr->shadow_stack_pos, &thr->shadow_stack[0]);
+  DCHECK_GE(thr->shadow_stack_pos, thr->shadow_stack);
 #ifndef TSAN_GO
-  DCHECK_LT(thr->shadow_stack_pos, &thr->shadow_stack[kShadowStackSize]);
+  DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
 #else
   if (thr->shadow_stack_pos == thr->shadow_stack_end) {
     const int sz = thr->shadow_stack_end - thr->shadow_stack;
@@ -688,9 +689,9 @@ void FuncExit(ThreadState *thr) {
   thr->fast_state.IncrementEpoch();
   TraceAddEvent(thr, thr->fast_state, EventTypeFuncExit, 0);
 
-  DCHECK_GT(thr->shadow_stack_pos, &thr->shadow_stack[0]);
+  DCHECK_GT(thr->shadow_stack_pos, thr->shadow_stack);
 #ifndef TSAN_GO
-  DCHECK_LT(thr->shadow_stack_pos, &thr->shadow_stack[kShadowStackSize]);
+  DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
 #endif
   thr->shadow_stack_pos--;
 }

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h?rev=192797&r1=192796&r2=192797&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h Wed Oct 16 10:35:12 2013
@@ -413,17 +413,13 @@ struct ThreadState {
   // for better performance.
   int ignore_reads_and_writes;
   int ignore_sync;
+  // C/C++ uses fixed size shadow stack embed into Trace.
+  // Go uses malloc-allocated shadow stack with dynamic size.
+  uptr *shadow_stack;
+  uptr *shadow_stack_end;
   uptr *shadow_stack_pos;
   u64 *racy_shadow_addr;
   u64 racy_state[2];
-#ifndef TSAN_GO
-  // C/C++ uses embed shadow stack of fixed size.
-  uptr shadow_stack[kShadowStackSize];
-#else
-  // Go uses satellite shadow stack with dynamic size.
-  uptr *shadow_stack;
-  uptr *shadow_stack_end;
-#endif
   MutexSet mset;
   ThreadClock clock;
 #ifndef TSAN_GO

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc?rev=192797&r1=192796&r2=192797&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc Wed Oct 16 10:35:12 2013
@@ -410,7 +410,7 @@ void RestoreStack(int tid, const u64 epo
   const u64 ebegin = RoundDown(eend, kTracePartSize);
   DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n",
           tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx);
-  InternalScopedBuffer<uptr> stack(1024);  // FIXME: de-hardcode 1024
+  InternalScopedBuffer<uptr> stack(kShadowStackSize);
   for (uptr i = 0; i < hdr->stack0.Size(); i++) {
     stack[i] = hdr->stack0.Get(i);
     DPrintf2("  #%02lu: pc=%zx\n", i, stack[i]);

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc?rev=192797&r1=192796&r2=192797&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc Wed Oct 16 10:35:12 2013
@@ -91,18 +91,21 @@ void ThreadContext::OnStarted(void *arg)
   epoch1 = (u64)-1;
   new(thr) ThreadState(CTX(), tid, unique_id,
       epoch0, args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
-#ifdef TSAN_GO
+#ifndef TSAN_GO
+  thr->shadow_stack = &ThreadTrace(thr->tid)->shadow_stack[0];
+  thr->shadow_stack_pos = thr->shadow_stack;
+  thr->shadow_stack_end = thr->shadow_stack + kShadowStackSize;
+#else
   // Setup dynamic shadow stack.
   const int kInitStackSize = 8;
-  args->thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
+  thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
       kInitStackSize * sizeof(uptr));
-  args->thr->shadow_stack_pos = thr->shadow_stack;
-  args->thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
+  thr->shadow_stack_pos = thr->shadow_stack;
+  thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
 #endif
 #ifndef TSAN_GO
-  AllocatorThreadStart(args->thr);
+  AllocatorThreadStart(thr);
 #endif
-  thr = args->thr;
   thr->fast_synch_epoch = epoch0;
   AcquireImpl(thr, 0, &sync);
   thr->fast_state.SetHistorySize(flags()->history_size);

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc?rev=192797&r1=192796&r2=192797&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc Wed Oct 16 10:35:12 2013
@@ -265,6 +265,11 @@ void StackTrace::ObtainCurrent(ThreadSta
       n_ = c_ - !!toppc;
     }
   } else {
+    // Cap potentially huge stacks.
+    if (n_ + !!toppc > kTraceStackSize) {
+      start = n_ - kTraceStackSize + !!toppc;
+      n_ = kTraceStackSize - !!toppc;
+    }
     s_ = (uptr*)internal_alloc(MBlockStackTrace,
                                (n_ + !!toppc) * sizeof(s_[0]));
   }

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_trace.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_trace.h?rev=192797&r1=192796&r2=192797&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_trace.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_trace.h Wed Oct 16 10:35:12 2013
@@ -62,6 +62,11 @@ struct TraceHeader {
 struct Trace {
   TraceHeader headers[kTraceParts];
   Mutex mtx;
+#ifndef TSAN_GO
+  // Must be last to catch overflow as paging fault.
+  // Go shadow stack is dynamically allocated.
+  uptr shadow_stack[kShadowStackSize];
+#endif
 
   Trace()
     : mtx(MutexTypeTrace, StatMtxTrace) {

Modified: compiler-rt/trunk/lib/tsan/tests/unit/tsan_stack_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/tests/unit/tsan_stack_test.cc?rev=192797&r1=192796&r2=192797&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/tests/unit/tsan_stack_test.cc (original)
+++ compiler-rt/trunk/lib/tsan/tests/unit/tsan_stack_test.cc Wed Oct 16 10:35:12 2013
@@ -19,6 +19,10 @@ namespace __tsan {
 
 static void TestStackTrace(StackTrace *trace) {
   ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0);
+  uptr stack[128];
+  thr.shadow_stack = &stack[0];
+  thr.shadow_stack_pos = &stack[0];
+  thr.shadow_stack_end = &stack[128];
 
   trace->ObtainCurrent(&thr, 0);
   EXPECT_EQ(trace->Size(), (uptr)0);
@@ -60,7 +64,12 @@ TEST(StackTrace, StaticTrim) {
   ScopedInRtl in_rtl;
   uptr buf[2];
   StackTrace trace(buf, 2);
+
   ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0);
+  uptr stack[128];
+  thr.shadow_stack = &stack[0];
+  thr.shadow_stack_pos = &stack[0];
+  thr.shadow_stack_end = &stack[128];
 
   *thr.shadow_stack_pos++ = 100;
   *thr.shadow_stack_pos++ = 101;





More information about the llvm-commits mailing list