123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- //===-- 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 <thread>.
- // 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_inplace<std::thread::_Impl\n";
- // Can be overriden in frontend.
- SANITIZER_WEAK_DEFAULT_IMPL
- const char *__tsan_default_suppressions() {
- return 0;
- }
- #endif
- namespace __tsan {
- ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
- static SuppressionContext *suppression_ctx = nullptr;
- static const char *kSuppressionTypes[] = {
- kSuppressionRace, kSuppressionRaceTop, kSuppressionMutex,
- kSuppressionThread, kSuppressionSignal, kSuppressionLib,
- kSuppressionDeadlock};
- void InitializeSuppressions() {
- CHECK_EQ(nullptr, suppression_ctx);
- suppression_ctx = new (suppression_placeholder)
- SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
- suppression_ctx->ParseFromFile(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<Suppression *> 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
|