tsan: allows to suppress races on global variables
llvm-svn: 183672
This commit is contained in:
parent
872b29794e
commit
315bb0e687
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue