//===-- tsan_suppressions.cc ----------------------------------------------===// // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_suppressions.h" #include "tsan_suppressions.h" #include "tsan_rtl.h" #include "tsan_flags.h" #include "tsan_mman.h" #include "tsan_platform.h" // Suppressions for true/false positives in standard libraries. static const char *const std_suppressions = // Libstdc++ 4.4 has data races in std::string. // See http://crbug.com/181502 for an example. "race:^_M_rep$\n" "race:^_M_is_leaked$\n" // False positive when using std . // Happens because we miss atomic synchronization in libstdc++. // See http://llvm.org/bugs/show_bug.cgi?id=17066 for details. "race:std::_Sp_counted_ptr_inplaceParse(__tsan_default_suppressions()); SuppressionContext::Get()->Parse(std_suppressions); #endif suppressions_inited = true; } SuppressionType conv(ReportType typ) { if (typ == ReportTypeRace) return SuppressionRace; else if (typ == ReportTypeVptrRace) return SuppressionRace; else if (typ == ReportTypeUseAfterFree) return SuppressionRace; else if (typ == ReportTypeVptrUseAfterFree) return SuppressionRace; else if (typ == ReportTypeThreadLeak) return SuppressionThread; else if (typ == ReportTypeMutexDestroyLocked) return SuppressionMutex; else if (typ == ReportTypeMutexDoubleLock) return SuppressionMutex; else if (typ == ReportTypeMutexBadUnlock) return SuppressionMutex; else if (typ == ReportTypeMutexBadReadLock) return SuppressionMutex; else if (typ == ReportTypeMutexBadReadUnlock) return SuppressionMutex; else if (typ == ReportTypeSignalUnsafe) return SuppressionSignal; else if (typ == ReportTypeErrnoInSignal) return SuppressionNone; else if (typ == ReportTypeDeadlock) return SuppressionDeadlock; Printf("ThreadSanitizer: unknown report type %d\n", typ), Die(); } uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) { if (!SuppressionContext::Get()->SuppressionCount() || stack == 0 || !stack->suppressable) return 0; SuppressionType stype = conv(typ); if (stype == SuppressionNone) return 0; Suppression *s; for (const ReportStack *frame = stack; frame; frame = frame->next) { const AddressInfo &info = frame->info; if (SuppressionContext::Get()->Match(info.function, stype, &s) || SuppressionContext::Get()->Match(info.file, stype, &s) || SuppressionContext::Get()->Match(info.module, stype, &s)) { DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ); s->hit_count++; *sp = s; return info.address; } } return 0; } uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) { if (!SuppressionContext::Get()->SuppressionCount() || loc == 0 || loc->type != ReportLocationGlobal || !loc->suppressable) return 0; SuppressionType stype = conv(typ); if (stype == SuppressionNone) return 0; Suppression *s; const DataInfo &global = loc->global; if (SuppressionContext::Get()->Match(global.name, stype, &s) || SuppressionContext::Get()->Match(global.module, stype, &s)) { DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ); s->hit_count++; *sp = s; return global.start; } return 0; } void PrintMatchedSuppressions() { InternalMmapVector matched(1); SuppressionContext::Get()->GetMatched(&matched); if (!matched.size()) return; int hit_count = 0; for (uptr i = 0; i < matched.size(); i++) hit_count += matched[i]->hit_count; Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count, (int)internal_getpid()); for (uptr i = 0; i < matched.size(); i++) { Printf("%d %s:%s\n", matched[i]->hit_count, SuppressionTypeString(matched[i]->type), matched[i]->templ); } } } // namespace __tsan