Index: lib/tsan/rtl/tsan_suppressions.h =================================================================== --- lib/tsan/rtl/tsan_suppressions.h +++ lib/tsan/rtl/tsan_suppressions.h @@ -20,6 +20,7 @@ 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"; Index: lib/tsan/rtl/tsan_suppressions.cc =================================================================== --- lib/tsan/rtl/tsan_suppressions.cc +++ lib/tsan/rtl/tsan_suppressions.cc @@ -44,8 +44,9 @@ 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); @@ -115,6 +116,17 @@ return info.address; } } + if (0 == internal_strcmp(stype, kSuppressionRace) && stack->frames != 0) { + const AddressInfo &info = stack->frames->info; + if (suppression_ctx->Match(info.function, kSuppressionRaceTop, &s) || + suppression_ctx->Match(info.file, kSuppressionRaceTop, &s) || + suppression_ctx->Match(info.module, kSuppressionRaceTop, &s)) { + DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ); + s->hit_count++; + *sp = s; + return info.address; + } + } return 0; } Index: test/tsan/race_top_suppression.cc =================================================================== --- test/tsan/race_top_suppression.cc +++ test/tsan/race_top_suppression.cc @@ -0,0 +1,26 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions='%s.supp'" %run %t 2>&1 | FileCheck %s +#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 Index: test/tsan/race_top_suppression.cc.supp =================================================================== --- test/tsan/race_top_suppression.cc.supp +++ test/tsan/race_top_suppression.cc.supp @@ -0,0 +1 @@ +race_top:TopFunction Index: test/tsan/race_top_suppression1.cc =================================================================== --- test/tsan/race_top_suppression1.cc +++ test/tsan/race_top_suppression1.cc @@ -0,0 +1,29 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions='%s.supp'" %deflake %run %t 2>&1 | FileCheck %s +#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 Index: test/tsan/race_top_suppression1.cc.supp =================================================================== --- test/tsan/race_top_suppression1.cc.supp +++ test/tsan/race_top_suppression1.cc.supp @@ -0,0 +1 @@ +race_top:TopFunction