tsan: refactor suppressions machinery

The refactoring makes suppressions more flexible
and allow to suppress based on arbitrary number of stacks.
In particular it fixes:
https://code.google.com/p/thread-sanitizer/issues/detail?id=64
"Make it possible to suppress deadlock reports by any stack (not just first)"

llvm-svn: 209757
This commit is contained in:
Dmitry Vyukov 2014-05-28 18:03:32 +00:00
parent 303934ba49
commit a43e98cc74
8 changed files with 41 additions and 43 deletions

View File

@ -1704,8 +1704,8 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool sigact,
ThreadRegistryLock l(ctx->thread_registry);
ScopedReport rep(ReportTypeErrnoInSignal);
if (!IsFiredSuppression(ctx, rep, stack)) {
rep.AddStack(&stack);
OutputReport(ctx, rep, rep.GetReport()->stacks[0]);
rep.AddStack(&stack, true);
OutputReport(ctx, rep);
}
}
errno = saved_errno;

View File

@ -95,8 +95,8 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
ThreadRegistryLock l(ctx->thread_registry);
ScopedReport rep(ReportTypeSignalUnsafe);
if (!IsFiredSuppression(ctx, rep, stack)) {
rep.AddStack(&stack);
OutputReport(ctx, rep, rep.GetReport()->stacks[0]);
rep.AddStack(&stack, true);
OutputReport(ctx, rep);
}
}

View File

@ -42,6 +42,7 @@ struct ReportStack {
char *file;
int line;
int col;
bool suppressable;
};
struct ReportMopMutex {
@ -80,6 +81,7 @@ struct ReportLocation {
char *name;
char *file;
int line;
bool suppressable;
ReportStack *stack;
};

View File

@ -576,11 +576,11 @@ class ScopedReport {
explicit ScopedReport(ReportType typ);
~ScopedReport();
void AddStack(const StackTrace *stack);
void AddMemoryAccess(uptr addr, Shadow s, const StackTrace *stack,
const MutexSet *mset);
void AddThread(const ThreadContext *tctx);
void AddThread(int unique_tid);
void AddStack(const StackTrace *stack, bool suppressable = false);
void AddThread(const ThreadContext *tctx, bool suppressable = false);
void AddThread(int unique_tid, bool suppressable = false);
void AddUniqueTid(int unique_tid);
void AddMutex(const SyncVar *s);
u64 AddMutex(u64 id);
@ -628,11 +628,7 @@ void ForkParentAfter(ThreadState *thr, uptr pc);
void ForkChildAfter(ThreadState *thr, uptr pc);
void ReportRace(ThreadState *thr);
bool OutputReport(Context *ctx,
const ScopedReport &srep,
const ReportStack *suppress_stack1,
const ReportStack *suppress_stack2 = 0,
const ReportLocation *suppress_loc = 0);
bool OutputReport(Context *ctx, const ScopedReport &srep);
bool IsFiredSuppression(Context *ctx,
const ScopedReport &srep,
const StackTrace &trace);

View File

@ -57,9 +57,9 @@ static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
rep.AddMutex(mid);
StackTrace trace;
trace.ObtainCurrent(thr, pc);
rep.AddStack(&trace);
rep.AddStack(&trace, true);
rep.AddLocation(addr, 1);
OutputReport(ctx, rep, rep.GetReport()->stacks[0]);
OutputReport(ctx, rep);
}
void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
@ -113,9 +113,9 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
rep.AddStack(&trace);
FastState last(s->last_lock);
RestoreStack(last.tid(), last.epoch(), &trace, 0);
rep.AddStack(&trace);
rep.AddStack(&trace, true);
rep.AddLocation(s->addr, 1);
OutputReport(ctx, rep, rep.GetReport()->stacks[0]);
OutputReport(ctx, rep);
}
thr->mset.Remove(s->GetId());
DestroyAndFree(s);
@ -462,12 +462,10 @@ void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
// but we should still produce some stack trace in the report.
stacks[i].Init(&dummy_pc, 1);
}
rep.AddStack(&stacks[i]);
rep.AddStack(&stacks[i], true);
}
}
// FIXME: use all stacks for suppressions, not just the second stack of the
// first edge.
OutputReport(ctx, rep, rep.GetReport()->stacks[0]);
OutputReport(ctx, rep);
}
} // namespace __tsan

View File

@ -162,9 +162,10 @@ ScopedReport::~ScopedReport() {
DestroyAndFree(rep_);
}
void ScopedReport::AddStack(const StackTrace *stack) {
void ScopedReport::AddStack(const StackTrace *stack, bool suppressable) {
ReportStack **rs = rep_->stacks.PushBack();
*rs = SymbolizeStack(*stack);
(*rs)->suppressable = suppressable;
}
void ScopedReport::AddMemoryAccess(uptr addr, Shadow s,
@ -178,6 +179,7 @@ void ScopedReport::AddMemoryAccess(uptr addr, Shadow s,
mop->write = s.IsWrite();
mop->atomic = s.IsAtomic();
mop->stack = SymbolizeStack(*stack);
mop->stack->suppressable = true;
for (uptr i = 0; i < mset->Size(); i++) {
MutexSet::Desc d = mset->Get(i);
u64 mid = this->AddMutex(d.id);
@ -190,7 +192,7 @@ void ScopedReport::AddUniqueTid(int unique_tid) {
rep_->unique_tids.PushBack(unique_tid);
}
void ScopedReport::AddThread(const ThreadContext *tctx) {
void ScopedReport::AddThread(const ThreadContext *tctx, bool suppressable) {
for (uptr i = 0; i < rep_->threads.Size(); i++) {
if ((u32)rep_->threads[i]->id == tctx->tid)
return;
@ -205,6 +207,8 @@ void ScopedReport::AddThread(const ThreadContext *tctx) {
rt->parent_tid = tctx->parent_tid;
rt->stack = 0;
rt->stack = SymbolizeStackId(tctx->creation_stack_id);
if (rt->stack)
rt->stack->suppressable = suppressable;
}
#ifndef TSAN_GO
@ -251,9 +255,9 @@ ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack) {
}
#endif
void ScopedReport::AddThread(int unique_tid) {
void ScopedReport::AddThread(int unique_tid, bool suppressable) {
#ifndef TSAN_GO
AddThread(FindThreadByUidLocked(unique_tid));
AddThread(FindThreadByUidLocked(unique_tid), suppressable);
#endif
}
@ -356,6 +360,7 @@ void ScopedReport::AddLocation(uptr addr, uptr size) {
}
ReportLocation *loc = SymbolizeData(addr);
if (loc) {
loc->suppressable = true;
rep_->locs.PushBack(loc);
return;
}
@ -495,19 +500,19 @@ 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 ReportLocation *suppress_loc) {
bool OutputReport(Context *ctx, const ScopedReport &srep) {
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);
uptr suppress_pc = 0;
for (uptr i = 0; suppress_pc == 0 && i < rep->mops.Size(); i++)
suppress_pc = IsSuppressed(rep->typ, rep->mops[i]->stack, &supp);
for (uptr i = 0; suppress_pc == 0 && i < rep->stacks.Size(); i++)
suppress_pc = IsSuppressed(rep->typ, rep->stacks[i], &supp);
for (uptr i = 0; suppress_pc == 0 && i < rep->threads.Size(); i++)
suppress_pc = IsSuppressed(rep->typ, rep->threads[i]->stack, &supp);
for (uptr i = 0; suppress_pc == 0 && i < rep->locs.Size(); i++)
suppress_pc = IsSuppressed(rep->typ, rep->locs[i], &supp);
if (suppress_pc != 0) {
FiredSuppression s = {srep.GetReport()->typ, suppress_pc, supp};
ctx->fired_suppressions.push_back(s);
@ -695,11 +700,7 @@ 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,
suppress_loc))
if (!OutputReport(ctx, rep))
return;
AddRacyStacks(thr, traces, addr_min, addr_max);

View File

@ -205,9 +205,9 @@ void ThreadFinalize(ThreadState *thr) {
MaybeReportThreadLeak, &leaks);
for (uptr i = 0; i < leaks.Size(); i++) {
ScopedReport rep(ReportTypeThreadLeak);
rep.AddThread(leaks[i].tctx);
rep.AddThread(leaks[i].tctx, true);
rep.SetCount(leaks[i].count);
OutputReport(ctx, rep, rep.GetReport()->threads[0]->stack);
OutputReport(ctx, rep);
}
#endif
}

View File

@ -123,7 +123,8 @@ SuppressionType conv(ReportType typ) {
uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
CHECK(g_ctx);
if (!g_ctx->SuppressionCount() || stack == 0) return 0;
if (!g_ctx->SuppressionCount() || stack == 0 || !stack->suppressable)
return 0;
SuppressionType stype = conv(typ);
if (stype == SuppressionNone)
return 0;
@ -144,7 +145,7 @@ uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
CHECK(g_ctx);
if (!g_ctx->SuppressionCount() || loc == 0 ||
loc->type != ReportLocationGlobal)
loc->type != ReportLocationGlobal || !loc->suppressable)
return 0;
SuppressionType stype = conv(typ);
if (stype == SuppressionNone)