[compiler-rt] r192797 - tsan: move shadow stack from thread descriptors to fixed addresses
Kostya Serebryany
kcc at google.com
Wed Oct 16 23:42:43 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)
>
Instead of having two different files that differ by one sleep(), I suggest
to have a single file,
where the sleep is under if statement and the test is run twice.
> +++ 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;
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20131017/1505853c/attachment.html>
More information about the llvm-commits
mailing list