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

llvm-svn: 240949
This commit is contained in:
Dmitry Vyukov 2015-06-29 14:38:31 +00:00
parent 0fc26d21bd
commit ffb551b2b0
4 changed files with 83 additions and 13 deletions

View File

@ -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;
}

View File

@ -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";

View File

@ -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

View File

@ -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