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