tsan: allows to suppress races on global variables

llvm-svn: 183672
This commit is contained in:
Dmitry Vyukov 2013-06-10 15:38:44 +00:00
parent 872b29794e
commit 315bb0e687
4 changed files with 74 additions and 19 deletions

View File

@ -602,7 +602,8 @@ void ReportRace(ThreadState *thr);
bool OutputReport(Context *ctx,
const ScopedReport &srep,
const ReportStack *suppress_stack1 = 0,
const ReportStack *suppress_stack2 = 0);
const ReportStack *suppress_stack2 = 0,
const ReportLocation *suppress_loc = 0);
bool IsFiredSuppression(Context *ctx,
const ScopedReport &srep,
const StackTrace &trace);

View File

@ -502,13 +502,16 @@ static void AddRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
bool OutputReport(Context *ctx,
const ScopedReport &srep,
const ReportStack *suppress_stack1,
const ReportStack *suppress_stack2) {
const ReportStack *suppress_stack2,
const ReportLocation *suppress_loc) {
atomic_store(&ctx->last_symbolize_time_ns, NanoTime(), memory_order_relaxed);
const ReportDesc *rep = srep.GetReport();
Suppression *supp = 0;
uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack1, &supp);
if (suppress_pc == 0)
suppress_pc = IsSuppressed(rep->typ, suppress_stack2, &supp);
if (suppress_pc == 0)
suppress_pc = IsSuppressed(rep->typ, suppress_loc, &supp);
if (suppress_pc != 0) {
FiredSuppression s = {srep.GetReport()->typ, suppress_pc, supp};
ctx->fired_suppressions.PushBack(s);
@ -538,6 +541,22 @@ bool IsFiredSuppression(Context *ctx,
return false;
}
static bool IsFiredSuppression(Context *ctx,
const ScopedReport &srep,
uptr addr) {
for (uptr k = 0; k < ctx->fired_suppressions.Size(); k++) {
if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
continue;
FiredSuppression *s = &ctx->fired_suppressions[k];
if (addr == s->pc) {
if (s->supp)
s->supp->hit_count++;
return true;
}
}
return false;
}
bool FrameIsInternal(const ReportStack *frame) {
return frame != 0 && frame->file != 0
&& (internal_strstr(frame->file, "tsan_interceptors.cc") ||
@ -631,6 +650,8 @@ void ReportRace(ThreadState *thr) {
else if (freed)
typ = ReportTypeUseAfterFree;
ScopedReport rep(typ);
if (IsFiredSuppression(ctx, rep, addr))
return;
const uptr kMop = 2;
StackTrace traces[kMop];
const uptr toppc = TraceTopPC(thr);
@ -641,6 +662,8 @@ void ReportRace(ThreadState *thr) {
new(mset2.data()) MutexSet();
Shadow s2(thr->racy_state[1]);
RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2.data());
if (IsFiredSuppression(ctx, rep, traces[1]))
return;
if (HandleRacyStacks(thr, traces, addr_min, addr_max))
return;
@ -673,8 +696,11 @@ void ReportRace(ThreadState *thr) {
}
#endif
ReportLocation *suppress_loc = rep.GetReport()->locs.Size() ?
rep.GetReport()->locs[0] : 0;
if (!OutputReport(ctx, rep, rep.GetReport()->mops[0]->stack,
rep.GetReport()->mops[1]->stack))
rep.GetReport()->mops[1]->stack,
suppress_loc))
return;
AddRacyStacks(thr, traces, addr_min, addr_max);

View File

@ -146,26 +146,31 @@ void InitializeSuppressions() {
#endif
}
SuppressionType conv(ReportType typ) {
if (typ == ReportTypeRace)
return SuppressionRace;
else if (typ == ReportTypeVptrRace)
return SuppressionRace;
else if (typ == ReportTypeUseAfterFree)
return SuppressionNone;
else if (typ == ReportTypeThreadLeak)
return SuppressionThread;
else if (typ == ReportTypeMutexDestroyLocked)
return SuppressionMutex;
else if (typ == ReportTypeSignalUnsafe)
return SuppressionSignal;
else if (typ == ReportTypeErrnoInSignal)
return SuppressionNone;
Printf("ThreadSanitizer: unknown report type %d\n", typ),
Die();
}
uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
if (g_suppressions == 0 || stack == 0)
return 0;
SuppressionType stype;
if (typ == ReportTypeRace)
stype = SuppressionRace;
else if (typ == ReportTypeVptrRace)
stype = SuppressionRace;
else if (typ == ReportTypeUseAfterFree)
SuppressionType stype = conv(typ);
if (stype == SuppressionNone)
return 0;
else if (typ == ReportTypeThreadLeak)
stype = SuppressionThread;
else if (typ == ReportTypeMutexDestroyLocked)
stype = SuppressionMutex;
else if (typ == ReportTypeSignalUnsafe)
stype = SuppressionSignal;
else if (typ == ReportTypeErrnoInSignal)
return 0;
else
Printf("ThreadSanitizer: unknown report type %d\n", typ), Die();
for (const ReportStack *frame = stack; frame; frame = frame->next) {
for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
if (stype == supp->type &&
@ -182,8 +187,29 @@ uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
return 0;
}
uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
if (g_suppressions == 0 || loc == 0 || loc->type != ReportLocationGlobal)
return 0;
SuppressionType stype = conv(typ);
if (stype == SuppressionNone)
return 0;
for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
if (stype == supp->type &&
(SuppressionMatch(supp->templ, loc->name) ||
SuppressionMatch(supp->templ, loc->file) ||
SuppressionMatch(supp->templ, loc->module))) {
DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
supp->hit_count++;
*sp = supp;
return loc->addr;
}
}
return 0;
}
static const char *SuppTypeStr(SuppressionType t) {
switch (t) {
case SuppressionNone: return "none";
case SuppressionRace: return "race";
case SuppressionMutex: return "mutex";
case SuppressionThread: return "thread";

View File

@ -19,6 +19,7 @@ namespace __tsan {
// Exposed for testing.
enum SuppressionType {
SuppressionNone,
SuppressionRace,
SuppressionMutex,
SuppressionThread,
@ -36,6 +37,7 @@ void InitializeSuppressions();
void FinalizeSuppressions();
void PrintMatchedSuppressions();
uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp);
uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp);
Suppression *SuppressionParse(Suppression *head, const char* supp);
bool SuppressionMatch(char *templ, const char *str);