summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2015-06-29 14:38:31 +0000
committerDmitry Vyukov <dvyukov@google.com>2015-06-29 14:38:31 +0000
commit26dea67f7bbefb3e16fa3101786952588206842f (patch)
treed554545e6f4f894030811d118b20acbf62826119
parent33ece059235b82a1390e9e7aabb9b7a1bb7a8ff7 (diff)
downloadcompiler-rt-26dea67f7bbefb3e16fa3101786952588206842f.tar.gz
tsan: implement suppressions for top frame only
The new suppression type is called "race_top" and is matched only against top frame in report stacks. This is required for situations when we want to suppress a race in a "thread pool" or "event loop" implementation. If we simply use "race:ThreadPool::Execute" suppression, that can suppress everything in the program. Reviewed in http://reviews.llvm.org/D10686 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@240949 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/tsan/rtl/tsan_suppressions.cc34
-rw-r--r--lib/tsan/rtl/tsan_suppressions.h1
-rw-r--r--test/tsan/race_top_suppression.cc29
-rw-r--r--test/tsan/race_top_suppression1.cc32
4 files changed, 83 insertions, 13 deletions
diff --git a/lib/tsan/rtl/tsan_suppressions.cc b/lib/tsan/rtl/tsan_suppressions.cc
index 731572980..e382f21f0 100644
--- a/lib/tsan/rtl/tsan_suppressions.cc
+++ b/lib/tsan/rtl/tsan_suppressions.cc
@@ -44,8 +44,9 @@ namespace __tsan {
ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
static SuppressionContext *suppression_ctx = nullptr;
static const char *kSuppressionTypes[] = {
- kSuppressionRace, kSuppressionMutex, kSuppressionThread,
- kSuppressionSignal, kSuppressionLib, kSuppressionDeadlock};
+ kSuppressionRace, kSuppressionRaceTop, kSuppressionMutex,
+ kSuppressionThread, kSuppressionSignal, kSuppressionLib,
+ kSuppressionDeadlock};
void InitializeSuppressions() {
CHECK_EQ(nullptr, suppression_ctx);
@@ -94,6 +95,18 @@ static const char *conv(ReportType typ) {
Die();
}
+static uptr IsSuppressed(const char *stype, const AddressInfo &info,
+ Suppression **sp) {
+ if (suppression_ctx->Match(info.function, stype, sp) ||
+ suppression_ctx->Match(info.file, stype, sp) ||
+ suppression_ctx->Match(info.module, stype, sp)) {
+ DPrintf("ThreadSanitizer: matched suppression '%s'\n", (*sp)->templ);
+ (*sp)->hit_count++;
+ return info.address;
+ }
+ return 0;
+}
+
uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
CHECK(suppression_ctx);
if (!suppression_ctx->SuppressionCount() || stack == 0 ||
@@ -102,19 +115,14 @@ uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
const char *stype = conv(typ);
if (0 == internal_strcmp(stype, kSuppressionNone))
return 0;
- Suppression *s;
for (const SymbolizedStack *frame = stack->frames; frame;
- frame = frame->next) {
- const AddressInfo &info = frame->info;
- if (suppression_ctx->Match(info.function, stype, &s) ||
- suppression_ctx->Match(info.file, stype, &s) ||
- suppression_ctx->Match(info.module, stype, &s)) {
- DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
- s->hit_count++;
- *sp = s;
- return info.address;
- }
+ frame = frame->next) {
+ uptr pc = IsSuppressed(stype, frame->info, sp);
+ if (pc != 0)
+ return pc;
}
+ if (0 == internal_strcmp(stype, kSuppressionRace) && stack->frames != nullptr)
+ return IsSuppressed(kSuppressionRaceTop, stack->frames->info, sp);
return 0;
}
diff --git a/lib/tsan/rtl/tsan_suppressions.h b/lib/tsan/rtl/tsan_suppressions.h
index e6d279c33..526952d5b 100644
--- a/lib/tsan/rtl/tsan_suppressions.h
+++ b/lib/tsan/rtl/tsan_suppressions.h
@@ -20,6 +20,7 @@ namespace __tsan {
const char kSuppressionNone[] = "none";
const char kSuppressionRace[] = "race";
+const char kSuppressionRaceTop[] = "race_top";
const char kSuppressionMutex[] = "mutex";
const char kSuppressionThread[] = "thread";
const char kSuppressionSignal[] = "signal";
diff --git a/test/tsan/race_top_suppression.cc b/test/tsan/race_top_suppression.cc
new file mode 100644
index 000000000..7d42dbf3b
--- /dev/null
+++ b/test/tsan/race_top_suppression.cc
@@ -0,0 +1,29 @@
+// RUN: echo "race_top:TopFunction" > %t.supp
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions='%t.supp'" %run %t 2>&1 | FileCheck %s
+// RUN: rm %t.supp
+#include "test.h"
+
+int Global;
+
+void TopFunction(int *p) {
+ *p = 1;
+}
+
+void *Thread(void *x) {
+ barrier_wait(&barrier);
+ TopFunction(&Global);
+ return 0;
+}
+
+int main() {
+ barrier_init(&barrier, 2);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ Global--;
+ barrier_wait(&barrier);
+ pthread_join(t, 0);
+ fprintf(stderr, "DONE\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/race_top_suppression1.cc b/test/tsan/race_top_suppression1.cc
new file mode 100644
index 000000000..881e661ba
--- /dev/null
+++ b/test/tsan/race_top_suppression1.cc
@@ -0,0 +1,32 @@
+// RUN: echo "race_top:TopFunction" > %t.supp
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions='%t.supp'" %deflake %run %t 2>&1 | FileCheck %s
+// RUN: rm %t.supp
+#include "test.h"
+
+int Global;
+
+void AnotherFunction(int *p) {
+ *p = 1;
+}
+
+void TopFunction(int *p) {
+ AnotherFunction(p);
+}
+
+void *Thread(void *x) {
+ barrier_wait(&barrier);
+ TopFunction(&Global);
+ return 0;
+}
+
+int main() {
+ barrier_init(&barrier, 2);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ Global--;
+ barrier_wait(&barrier);
+ pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race