From 26dea67f7bbefb3e16fa3101786952588206842f Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 29 Jun 2015 14:38:31 +0000 Subject: 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 --- lib/tsan/rtl/tsan_suppressions.cc | 34 +++++++++++++++++++++------------- lib/tsan/rtl/tsan_suppressions.h | 1 + test/tsan/race_top_suppression.cc | 29 +++++++++++++++++++++++++++++ test/tsan/race_top_suppression1.cc | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 13 deletions(-) create mode 100644 test/tsan/race_top_suppression.cc create mode 100644 test/tsan/race_top_suppression1.cc 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 -- cgit v1.2.1