summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler-rt/lib/tsan/lit_tests/deep_stack0.cc38
-rw-r--r--compiler-rt/lib/tsan/lit_tests/deep_stack1.cc38
-rw-r--r--compiler-rt/lib/tsan/lit_tests/global_race.cc10
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_defs.h6
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_platform.h10
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl.cc15
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl.h12
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc2
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc15
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_sync.cc5
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_trace.h5
-rw-r--r--compiler-rt/lib/tsan/tests/unit/tsan_stack_test.cc9
12 files changed, 132 insertions, 33 deletions
diff --git a/compiler-rt/lib/tsan/lit_tests/deep_stack0.cc b/compiler-rt/lib/tsan/lit_tests/deep_stack0.cc
new file mode 100644
index 00000000000..7c0a8161a3f
--- /dev/null
+++ b/compiler-rt/lib/tsan/lit_tests/deep_stack0.cc
@@ -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)
+
diff --git a/compiler-rt/lib/tsan/lit_tests/deep_stack1.cc b/compiler-rt/lib/tsan/lit_tests/deep_stack1.cc
new file mode 100644
index 00000000000..929f1e6039a
--- /dev/null
+++ b/compiler-rt/lib/tsan/lit_tests/deep_stack1.cc
@@ -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)
+
diff --git a/compiler-rt/lib/tsan/lit_tests/global_race.cc b/compiler-rt/lib/tsan/lit_tests/global_race.cc
index 3e26792d8d6..cbe9f147221 100644
--- a/compiler-rt/lib/tsan/lit_tests/global_race.cc
+++ b/compiler-rt/lib/tsan/lit_tests/global_race.cc
@@ -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]+}})
diff --git a/compiler-rt/lib/tsan/rtl/tsan_defs.h b/compiler-rt/lib/tsan/rtl/tsan_defs.h
index 27f1db38f3a..1e53a8e02f0 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_defs.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_defs.h
@@ -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 \
diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform.h b/compiler-rt/lib/tsan/rtl/tsan_platform.h
index 70e1183afa2..32e22ba6043 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_platform.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_platform.h
@@ -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;
}
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl.cc
index dcaf071460d..22cf3cfc853 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cc
@@ -90,7 +90,6 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
// 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--;
}
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
index fc12f5d765d..14d97df4075 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -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
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
index bc26b6366c5..c353cea879c 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
@@ -410,7 +410,7 @@ void RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset) {
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]);
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
index 3ed1457ef1e..4e451b04294 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
@@ -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);
diff --git a/compiler-rt/lib/tsan/rtl/tsan_sync.cc b/compiler-rt/lib/tsan/rtl/tsan_sync.cc
index c6ddcdb3742..f8f3c40fab0 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_sync.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_sync.cc
@@ -265,6 +265,11 @@ void StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) {
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]));
}
diff --git a/compiler-rt/lib/tsan/rtl/tsan_trace.h b/compiler-rt/lib/tsan/rtl/tsan_trace.h
index 7df71604656..5ed0356e2bf 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_trace.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_trace.h
@@ -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) {
diff --git a/compiler-rt/lib/tsan/tests/unit/tsan_stack_test.cc b/compiler-rt/lib/tsan/tests/unit/tsan_stack_test.cc
index d5392959c48..9aa2967628c 100644
--- a/compiler-rt/lib/tsan/tests/unit/tsan_stack_test.cc
+++ b/compiler-rt/lib/tsan/tests/unit/tsan_stack_test.cc
@@ -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;
OpenPOWER on IntegriCloud