1 1.1 mrg //===-- tsan_suppressions.cpp ---------------------------------------------===// 2 1.1 mrg // 3 1.1 mrg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 1.1 mrg // See https://llvm.org/LICENSE.txt for license information. 5 1.1 mrg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 1.1 mrg // 7 1.1 mrg //===----------------------------------------------------------------------===// 8 1.1 mrg // 9 1.1 mrg // This file is a part of ThreadSanitizer (TSan), a race detector. 10 1.1 mrg // 11 1.1 mrg //===----------------------------------------------------------------------===// 12 1.1 mrg 13 1.4 mrg #include "tsan_suppressions.h" 14 1.4 mrg 15 1.1 mrg #include "sanitizer_common/sanitizer_common.h" 16 1.1 mrg #include "sanitizer_common/sanitizer_libc.h" 17 1.1 mrg #include "sanitizer_common/sanitizer_placement_new.h" 18 1.1 mrg #include "sanitizer_common/sanitizer_suppressions.h" 19 1.1 mrg #include "tsan_flags.h" 20 1.1 mrg #include "tsan_mman.h" 21 1.1 mrg #include "tsan_platform.h" 22 1.4 mrg #include "tsan_rtl.h" 23 1.1 mrg 24 1.1 mrg #if !SANITIZER_GO 25 1.1 mrg // Suppressions for true/false positives in standard libraries. 26 1.1 mrg static const char *const std_suppressions = 27 1.1 mrg // Libstdc++ 4.4 has data races in std::string. 28 1.1 mrg // See http://crbug.com/181502 for an example. 29 1.1 mrg "race:^_M_rep$\n" 30 1.1 mrg "race:^_M_is_leaked$\n" 31 1.1 mrg // False positive when using std <thread>. 32 1.1 mrg // Happens because we miss atomic synchronization in libstdc++. 33 1.1 mrg // See http://llvm.org/bugs/show_bug.cgi?id=17066 for details. 34 1.1 mrg "race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n"; 35 1.1 mrg 36 1.1 mrg // Can be overriden in frontend. 37 1.1 mrg SANITIZER_WEAK_DEFAULT_IMPL 38 1.1 mrg const char *__tsan_default_suppressions() { 39 1.1 mrg return 0; 40 1.1 mrg } 41 1.1 mrg #endif 42 1.1 mrg 43 1.1 mrg namespace __tsan { 44 1.1 mrg 45 1.1 mrg ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)]; 46 1.1 mrg static SuppressionContext *suppression_ctx = nullptr; 47 1.1 mrg static const char *kSuppressionTypes[] = { 48 1.1 mrg kSuppressionRace, kSuppressionRaceTop, kSuppressionMutex, 49 1.1 mrg kSuppressionThread, kSuppressionSignal, kSuppressionLib, 50 1.1 mrg kSuppressionDeadlock}; 51 1.1 mrg 52 1.1 mrg void InitializeSuppressions() { 53 1.1 mrg CHECK_EQ(nullptr, suppression_ctx); 54 1.1 mrg suppression_ctx = new (suppression_placeholder) 55 1.1 mrg SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); 56 1.1 mrg suppression_ctx->ParseFromFile(flags()->suppressions); 57 1.1 mrg #if !SANITIZER_GO 58 1.1 mrg suppression_ctx->Parse(__tsan_default_suppressions()); 59 1.1 mrg suppression_ctx->Parse(std_suppressions); 60 1.1 mrg #endif 61 1.1 mrg } 62 1.1 mrg 63 1.1 mrg SuppressionContext *Suppressions() { 64 1.1 mrg CHECK(suppression_ctx); 65 1.1 mrg return suppression_ctx; 66 1.1 mrg } 67 1.1 mrg 68 1.1 mrg static const char *conv(ReportType typ) { 69 1.1 mrg switch (typ) { 70 1.1 mrg case ReportTypeRace: 71 1.1 mrg case ReportTypeVptrRace: 72 1.1 mrg case ReportTypeUseAfterFree: 73 1.1 mrg case ReportTypeVptrUseAfterFree: 74 1.1 mrg case ReportTypeExternalRace: 75 1.1 mrg return kSuppressionRace; 76 1.1 mrg case ReportTypeThreadLeak: 77 1.1 mrg return kSuppressionThread; 78 1.1 mrg case ReportTypeMutexDestroyLocked: 79 1.1 mrg case ReportTypeMutexDoubleLock: 80 1.1 mrg case ReportTypeMutexInvalidAccess: 81 1.1 mrg case ReportTypeMutexBadUnlock: 82 1.1 mrg case ReportTypeMutexBadReadLock: 83 1.1 mrg case ReportTypeMutexBadReadUnlock: 84 1.4 mrg case ReportTypeMutexHeldWrongContext: 85 1.1 mrg return kSuppressionMutex; 86 1.1 mrg case ReportTypeSignalUnsafe: 87 1.1 mrg case ReportTypeErrnoInSignal: 88 1.1 mrg return kSuppressionSignal; 89 1.1 mrg case ReportTypeDeadlock: 90 1.1 mrg return kSuppressionDeadlock; 91 1.1 mrg // No default case so compiler warns us if we miss one 92 1.1 mrg } 93 1.1 mrg UNREACHABLE("missing case"); 94 1.1 mrg } 95 1.1 mrg 96 1.1 mrg static uptr IsSuppressed(const char *stype, const AddressInfo &info, 97 1.1 mrg Suppression **sp) { 98 1.1 mrg if (suppression_ctx->Match(info.function, stype, sp) || 99 1.1 mrg suppression_ctx->Match(info.file, stype, sp) || 100 1.1 mrg suppression_ctx->Match(info.module, stype, sp)) { 101 1.1 mrg VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", (*sp)->templ); 102 1.1 mrg atomic_fetch_add(&(*sp)->hit_count, 1, memory_order_relaxed); 103 1.1 mrg return info.address; 104 1.1 mrg } 105 1.1 mrg return 0; 106 1.1 mrg } 107 1.1 mrg 108 1.1 mrg uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) { 109 1.1 mrg CHECK(suppression_ctx); 110 1.1 mrg if (!suppression_ctx->SuppressionCount() || stack == 0 || 111 1.1 mrg !stack->suppressable) 112 1.1 mrg return 0; 113 1.1 mrg const char *stype = conv(typ); 114 1.1 mrg if (0 == internal_strcmp(stype, kSuppressionNone)) 115 1.1 mrg return 0; 116 1.1 mrg for (const SymbolizedStack *frame = stack->frames; frame; 117 1.1 mrg frame = frame->next) { 118 1.1 mrg uptr pc = IsSuppressed(stype, frame->info, sp); 119 1.1 mrg if (pc != 0) 120 1.1 mrg return pc; 121 1.1 mrg } 122 1.1 mrg if (0 == internal_strcmp(stype, kSuppressionRace) && stack->frames != nullptr) 123 1.1 mrg return IsSuppressed(kSuppressionRaceTop, stack->frames->info, sp); 124 1.1 mrg return 0; 125 1.1 mrg } 126 1.1 mrg 127 1.1 mrg uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) { 128 1.1 mrg CHECK(suppression_ctx); 129 1.1 mrg if (!suppression_ctx->SuppressionCount() || loc == 0 || 130 1.1 mrg loc->type != ReportLocationGlobal || !loc->suppressable) 131 1.1 mrg return 0; 132 1.1 mrg const char *stype = conv(typ); 133 1.1 mrg if (0 == internal_strcmp(stype, kSuppressionNone)) 134 1.1 mrg return 0; 135 1.1 mrg Suppression *s; 136 1.1 mrg const DataInfo &global = loc->global; 137 1.1 mrg if (suppression_ctx->Match(global.name, stype, &s) || 138 1.1 mrg suppression_ctx->Match(global.module, stype, &s)) { 139 1.1 mrg VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", s->templ); 140 1.1 mrg atomic_fetch_add(&s->hit_count, 1, memory_order_relaxed); 141 1.1 mrg *sp = s; 142 1.1 mrg return global.start; 143 1.1 mrg } 144 1.1 mrg return 0; 145 1.1 mrg } 146 1.1 mrg 147 1.1 mrg void PrintMatchedSuppressions() { 148 1.1 mrg InternalMmapVector<Suppression *> matched; 149 1.1 mrg CHECK(suppression_ctx); 150 1.1 mrg suppression_ctx->GetMatched(&matched); 151 1.1 mrg if (!matched.size()) 152 1.1 mrg return; 153 1.1 mrg int hit_count = 0; 154 1.1 mrg for (uptr i = 0; i < matched.size(); i++) 155 1.1 mrg hit_count += atomic_load_relaxed(&matched[i]->hit_count); 156 1.1 mrg Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count, 157 1.1 mrg (int)internal_getpid()); 158 1.1 mrg for (uptr i = 0; i < matched.size(); i++) { 159 1.1 mrg Printf("%d %s:%s\n", atomic_load_relaxed(&matched[i]->hit_count), 160 1.1 mrg matched[i]->type, matched[i]->templ); 161 1.1 mrg } 162 1.1 mrg } 163 1.1 mrg } // namespace __tsan 164