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 // Suppressions for true/false positives in standard libraries. 25 static const char *const std_suppressions = 26 // Libstdc++ 4.4 has data races in std::string. 27 // See http://crbug.com/181502 for an example. 28 "race:^_M_rep$\n" 29 "race:^_M_is_leaked$\n" 30 // False positive when using std <thread>. 31 // Happens because we miss atomic synchronization in libstdc++. 32 // See http://llvm.org/bugs/show_bug.cgi?id=17066 for details. 33 "race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n"; 34 35 // Can be overriden in frontend. 36 #ifndef TSAN_GO 37 extern "C" const char *WEAK __tsan_default_suppressions() { 38 return 0; 39 } 40 #endif 41 42 namespace __tsan { 43 44 static SuppressionContext* g_ctx; 45 46 static char *ReadFile(const char *filename) { 47 if (filename == 0 || filename[0] == 0) 48 return 0; 49 InternalScopedBuffer<char> tmp(4*1024); 50 if (filename[0] == '/' || GetPwd() == 0) 51 internal_snprintf(tmp.data(), tmp.size(), "%s", filename); 52 else 53 internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename); 54 uptr openrv = OpenFile(tmp.data(), false); 55 if (internal_iserror(openrv)) { 56 Printf("ThreadSanitizer: failed to open suppressions file '%s'\n", 57 tmp.data()); 58 Die(); 59 } 60 fd_t fd = openrv; 61 const uptr fsize = internal_filesize(fd); 62 if (fsize == (uptr)-1) { 63 Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n", 64 tmp.data()); 65 Die(); 66 } 67 char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1); 68 if (fsize != internal_read(fd, buf, fsize)) { 69 Printf("ThreadSanitizer: failed to read suppressions file '%s'\n", 70 tmp.data()); 71 Die(); 72 } 73 internal_close(fd); 74 buf[fsize] = 0; 75 return buf; 76 } 77 78 void InitializeSuppressions() { 79 ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)]; 80 g_ctx = new(placeholder_) SuppressionContext; 81 const char *supp = ReadFile(flags()->suppressions); 82 g_ctx->Parse(supp); 83 #ifndef TSAN_GO 84 supp = __tsan_default_suppressions(); 85 g_ctx->Parse(supp); 86 g_ctx->Parse(std_suppressions); 87 #endif 88 } 89 90 SuppressionContext *GetSuppressionContext() { 91 CHECK_NE(g_ctx, 0); 92 return g_ctx; 93 } 94 95 SuppressionType conv(ReportType typ) { 96 if (typ == ReportTypeRace) 97 return SuppressionRace; 98 else if (typ == ReportTypeVptrRace) 99 return SuppressionRace; 100 else if (typ == ReportTypeUseAfterFree) 101 return SuppressionRace; 102 else if (typ == ReportTypeThreadLeak) 103 return SuppressionThread; 104 else if (typ == ReportTypeMutexDestroyLocked) 105 return SuppressionMutex; 106 else if (typ == ReportTypeMutexDoubleLock) 107 return SuppressionMutex; 108 else if (typ == ReportTypeMutexBadUnlock) 109 return SuppressionMutex; 110 else if (typ == ReportTypeMutexBadReadLock) 111 return SuppressionMutex; 112 else if (typ == ReportTypeMutexBadReadUnlock) 113 return SuppressionMutex; 114 else if (typ == ReportTypeSignalUnsafe) 115 return SuppressionSignal; 116 else if (typ == ReportTypeErrnoInSignal) 117 return SuppressionNone; 118 else if (typ == ReportTypeDeadlock) 119 return SuppressionDeadlock; 120 Printf("ThreadSanitizer: unknown report type %d\n", typ), 121 Die(); 122 } 123 124 uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) { 125 CHECK(g_ctx); 126 if (!g_ctx->SuppressionCount() || stack == 0 || !stack->suppressable) 127 return 0; 128 SuppressionType stype = conv(typ); 129 if (stype == SuppressionNone) 130 return 0; 131 Suppression *s; 132 for (const ReportStack *frame = stack; frame; frame = frame->next) { 133 if (g_ctx->Match(frame->func, stype, &s) || 134 g_ctx->Match(frame->file, stype, &s) || 135 g_ctx->Match(frame->module, stype, &s)) { 136 DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ); 137 s->hit_count++; 138 *sp = s; 139 return frame->pc; 140 } 141 } 142 return 0; 143 } 144 145 uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) { 146 CHECK(g_ctx); 147 if (!g_ctx->SuppressionCount() || loc == 0 || 148 loc->type != ReportLocationGlobal || !loc->suppressable) 149 return 0; 150 SuppressionType stype = conv(typ); 151 if (stype == SuppressionNone) 152 return 0; 153 Suppression *s; 154 if (g_ctx->Match(loc->name, stype, &s) || 155 g_ctx->Match(loc->file, stype, &s) || 156 g_ctx->Match(loc->module, stype, &s)) { 157 DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ); 158 s->hit_count++; 159 *sp = s; 160 return loc->addr; 161 } 162 return 0; 163 } 164 165 void PrintMatchedSuppressions() { 166 CHECK(g_ctx); 167 InternalMmapVector<Suppression *> matched(1); 168 g_ctx->GetMatched(&matched); 169 if (!matched.size()) 170 return; 171 int hit_count = 0; 172 for (uptr i = 0; i < matched.size(); i++) 173 hit_count += matched[i]->hit_count; 174 Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count, 175 (int)internal_getpid()); 176 for (uptr i = 0; i < matched.size(); i++) { 177 Printf("%d %s:%s\n", matched[i]->hit_count, 178 SuppressionTypeString(matched[i]->type), matched[i]->templ); 179 } 180 } 181 } // namespace __tsan 182