//===-- tsan_suppressions.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // 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" #if !SANITIZER_GO // 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_inplaceParseFromFile(flags()->suppressions); #if !SANITIZER_GO suppression_ctx->Parse(__tsan_default_suppressions()); suppression_ctx->Parse(std_suppressions); #endif } SuppressionContext *Suppressions() { CHECK(suppression_ctx); return suppression_ctx; } static const char *conv(ReportType typ) { switch (typ) { case ReportTypeRace: case ReportTypeVptrRace: case ReportTypeUseAfterFree: case ReportTypeVptrUseAfterFree: case ReportTypeExternalRace: return kSuppressionRace; case ReportTypeThreadLeak: return kSuppressionThread; case ReportTypeMutexDestroyLocked: case ReportTypeMutexDoubleLock: case ReportTypeMutexInvalidAccess: case ReportTypeMutexBadUnlock: case ReportTypeMutexBadReadLock: case ReportTypeMutexBadReadUnlock: return kSuppressionMutex; case ReportTypeSignalUnsafe: case ReportTypeErrnoInSignal: return kSuppressionSignal; case ReportTypeDeadlock: return kSuppressionDeadlock; // No default case so compiler warns us if we miss one } UNREACHABLE("missing case"); } 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)) { VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", (*sp)->templ); atomic_fetch_add(&(*sp)->hit_count, 1, memory_order_relaxed); return info.address; } return 0; } uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) { CHECK(suppression_ctx); if (!suppression_ctx->SuppressionCount() || stack == 0 || !stack->suppressable) return 0; const char *stype = conv(typ); if (0 == internal_strcmp(stype, kSuppressionNone)) return 0; for (const SymbolizedStack *frame = stack->frames; frame; 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; } uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) { CHECK(suppression_ctx); if (!suppression_ctx->SuppressionCount() || loc == 0 || loc->type != ReportLocationGlobal || !loc->suppressable) return 0; const char *stype = conv(typ); if (0 == internal_strcmp(stype, kSuppressionNone)) return 0; Suppression *s; const DataInfo &global = loc->global; if (suppression_ctx->Match(global.name, stype, &s) || suppression_ctx->Match(global.module, stype, &s)) { VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", s->templ); atomic_fetch_add(&s->hit_count, 1, memory_order_relaxed); *sp = s; return global.start; } return 0; } void PrintMatchedSuppressions() { InternalMmapVector matched; CHECK(suppression_ctx); suppression_ctx->GetMatched(&matched); if (!matched.size()) return; int hit_count = 0; for (uptr i = 0; i < matched.size(); i++) hit_count += atomic_load_relaxed(&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", atomic_load_relaxed(&matched[i]->hit_count), matched[i]->type, matched[i]->templ); } } } // namespace __tsan