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 // Can be overriden in frontend. 25 #ifndef TSAN_GO 26 extern "C" const char *WEAK __tsan_default_suppressions() { 27 return 0; 28 } 29 #endif 30 31 namespace __tsan { 32 33 static SuppressionContext* g_ctx; 34 35 static char *ReadFile(const char *filename) { 36 if (filename == 0 || filename[0] == 0) 37 return 0; 38 InternalScopedBuffer<char> tmp(4*1024); 39 if (filename[0] == '/' || GetPwd() == 0) 40 internal_snprintf(tmp.data(), tmp.size(), "%s", filename); 41 else 42 internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename); 43 uptr openrv = OpenFile(tmp.data(), false); 44 if (internal_iserror(openrv)) { 45 Printf("ThreadSanitizer: failed to open suppressions file '%s'\n", 46 tmp.data()); 47 Die(); 48 } 49 fd_t fd = openrv; 50 const uptr fsize = internal_filesize(fd); 51 if (fsize == (uptr)-1) { 52 Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n", 53 tmp.data()); 54 Die(); 55 } 56 char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1); 57 if (fsize != internal_read(fd, buf, fsize)) { 58 Printf("ThreadSanitizer: failed to read suppressions file '%s'\n", 59 tmp.data()); 60 Die(); 61 } 62 internal_close(fd); 63 buf[fsize] = 0; 64 return buf; 65 } 66 67 void InitializeSuppressions() { 68 ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)]; 69 g_ctx = new(placeholder_) SuppressionContext; 70 const char *supp = ReadFile(flags()->suppressions); 71 g_ctx->Parse(supp); 72 #ifndef TSAN_GO 73 supp = __tsan_default_suppressions(); 74 g_ctx->Parse(supp); 75 #endif 76 } 77 78 SuppressionType conv(ReportType typ) { 79 if (typ == ReportTypeRace) 80 return SuppressionRace; 81 else if (typ == ReportTypeVptrRace) 82 return SuppressionRace; 83 else if (typ == ReportTypeUseAfterFree) 84 return SuppressionRace; 85 else if (typ == ReportTypeThreadLeak) 86 return SuppressionThread; 87 else if (typ == ReportTypeMutexDestroyLocked) 88 return SuppressionMutex; 89 else if (typ == ReportTypeSignalUnsafe) 90 return SuppressionSignal; 91 else if (typ == ReportTypeErrnoInSignal) 92 return SuppressionNone; 93 Printf("ThreadSanitizer: unknown report type %d\n", typ), 94 Die(); 95 } 96 97 uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) { 98 CHECK(g_ctx); 99 if (!g_ctx->SuppressionCount() || stack == 0) return 0; 100 SuppressionType stype = conv(typ); 101 if (stype == SuppressionNone) 102 return 0; 103 Suppression *s; 104 for (const ReportStack *frame = stack; frame; frame = frame->next) { 105 if (g_ctx->Match(frame->func, stype, &s) || 106 g_ctx->Match(frame->file, stype, &s) || 107 g_ctx->Match(frame->module, stype, &s)) { 108 DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ); 109 s->hit_count++; 110 *sp = s; 111 return frame->pc; 112 } 113 } 114 return 0; 115 } 116 117 uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) { 118 CHECK(g_ctx); 119 if (!g_ctx->SuppressionCount() || loc == 0 || 120 loc->type != ReportLocationGlobal) 121 return 0; 122 SuppressionType stype = conv(typ); 123 if (stype == SuppressionNone) 124 return 0; 125 Suppression *s; 126 if (g_ctx->Match(loc->name, stype, &s) || 127 g_ctx->Match(loc->file, stype, &s) || 128 g_ctx->Match(loc->module, stype, &s)) { 129 DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ); 130 s->hit_count++; 131 *sp = s; 132 return loc->addr; 133 } 134 return 0; 135 } 136 137 void PrintMatchedSuppressions() { 138 CHECK(g_ctx); 139 InternalMmapVector<Suppression *> matched(1); 140 g_ctx->GetMatched(&matched); 141 if (!matched.size()) 142 return; 143 int hit_count = 0; 144 for (uptr i = 0; i < matched.size(); i++) 145 hit_count += matched[i]->hit_count; 146 Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count, 147 (int)internal_getpid()); 148 for (uptr i = 0; i < matched.size(); i++) { 149 Printf("%d %s:%s\n", matched[i]->hit_count, 150 SuppressionTypeString(matched[i]->type), matched[i]->templ); 151 } 152 } 153 } // namespace __tsan 154