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

Alexey Samsonov samsonov at google.com
Wed Oct 16 08:44:39 PDT 2013


On Wed, Oct 16, 2013 at 7:35 PM, Dmitry Vyukov <dvyukov at google.com> wrote:

> 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;
>

Why did you change this?


>  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;
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>



-- 
Alexey Samsonov, MSK
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20131016/6c299b41/attachment.html>


More information about the llvm-commits mailing list