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

Dmitry Vyukov dvyukov at google.com
Wed Oct 16 09:06:17 PDT 2013


Didn't know that I need to update llvm-symbolizer.
Reverted in r192798.

On Wed, Oct 16, 2013 at 7:44 PM, Alexey Samsonov <samsonov at google.com> wrote:
>
> 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



More information about the llvm-commits mailing list