tsan_suppressions.cc revision 67a64dd8259fdbd867633b27f54d584f435f1ce6
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_libc.h" 15#include "tsan_suppressions.h" 16#include "tsan_rtl.h" 17#include "tsan_flags.h" 18#include "tsan_mman.h" 19#include "tsan_platform.h" 20 21namespace __tsan { 22 23static Suppression *g_suppressions; 24 25static char *ReadFile(const char *filename) { 26 if (filename == 0 || filename[0] == 0) 27 return 0; 28 InternalScopedBuf<char> tmp(4*1024); 29 if (filename[0] == '/') 30 SNPrintf(tmp, tmp.Size(), "%s", filename); 31 else 32 SNPrintf(tmp, tmp.Size(), "%s/%s", internal_getpwd(), filename); 33 fd_t fd = internal_open(tmp, false); 34 if (fd == kInvalidFd) { 35 TsanPrintf("ThreadSanitizer: failed to open suppressions file '%s'\n", 36 tmp.Ptr()); 37 Die(); 38 } 39 const uptr fsize = internal_filesize(fd); 40 if (fsize == (uptr)-1) { 41 TsanPrintf("ThreadSanitizer: failed to stat suppressions file '%s'\n", 42 tmp.Ptr()); 43 Die(); 44 } 45 char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1); 46 if (fsize != internal_read(fd, buf, fsize)) { 47 TsanPrintf("ThreadSanitizer: failed to read suppressions file '%s'\n", 48 tmp.Ptr()); 49 Die(); 50 } 51 internal_close(fd); 52 buf[fsize] = 0; 53 return buf; 54} 55 56bool SuppressionMatch(char *templ, const char *str) { 57 if (str == 0 || str[0] == 0) 58 return false; 59 char *tpos; 60 const char *spos; 61 while (templ && templ[0]) { 62 if (templ[0] == '*') { 63 templ++; 64 continue; 65 } 66 if (str[0] == 0) 67 return false; 68 tpos = (char*)internal_strchr(templ, '*'); 69 if (tpos != 0) 70 tpos[0] = 0; 71 spos = internal_strstr(str, templ); 72 str = spos + internal_strlen(templ); 73 templ = tpos; 74 if (tpos) 75 tpos[0] = '*'; 76 if (spos == 0) 77 return false; 78 } 79 return true; 80} 81 82Suppression *SuppressionParse(const char* supp) { 83 Suppression *head = 0; 84 const char *line = supp; 85 while (line) { 86 while (line[0] == ' ' || line[0] == '\t') 87 line++; 88 const char *end = internal_strchr(line, '\n'); 89 if (end == 0) 90 end = line + internal_strlen(line); 91 if (line != end && line[0] != '#') { 92 const char *end2 = end; 93 while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t')) 94 end2--; 95 SuppressionType stype; 96 if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) { 97 stype = SuppressionRace; 98 line += sizeof("race:") - 1; 99 } else if (0 == internal_strncmp(line, "thread:", 100 sizeof("thread:") - 1)) { 101 stype = SuppressionThread; 102 line += sizeof("thread:") - 1; 103 } else if (0 == internal_strncmp(line, "mutex:", 104 sizeof("mutex:") - 1)) { 105 stype = SuppressionMutex; 106 line += sizeof("mutex:") - 1; 107 } else if (0 == internal_strncmp(line, "signal:", 108 sizeof("signal:") - 1)) { 109 stype = SuppressionSignal; 110 line += sizeof("signal:") - 1; 111 } else { 112 TsanPrintf("ThreadSanitizer: failed to parse suppressions file\n"); 113 Die(); 114 } 115 Suppression *s = (Suppression*)internal_alloc(MBlockSuppression, 116 sizeof(Suppression)); 117 s->next = head; 118 head = s; 119 s->type = stype; 120 s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1); 121 internal_memcpy(s->templ, line, end2 - line); 122 s->templ[end2 - line] = 0; 123 } 124 if (end[0] == 0) 125 break; 126 line = end + 1; 127 } 128 return head; 129} 130 131void InitializeSuppressions() { 132 char *supp = ReadFile(flags()->suppressions); 133 g_suppressions = SuppressionParse(supp); 134} 135 136bool IsSuppressed(ReportType typ, const ReportStack *stack) { 137 if (g_suppressions == 0 || stack == 0) 138 return false; 139 SuppressionType stype; 140 if (typ == ReportTypeRace) 141 stype = SuppressionRace; 142 else if (typ == ReportTypeThreadLeak) 143 stype = SuppressionThread; 144 else if (typ == ReportTypeMutexDestroyLocked) 145 stype = SuppressionMutex; 146 else if (typ == ReportTypeSignalUnsafe) 147 stype = SuppressionSignal; 148 else 149 return false; 150 for (const ReportStack *frame = stack; frame; frame = frame->next) { 151 for (Suppression *supp = g_suppressions; supp; supp = supp->next) { 152 if (stype == supp->type && 153 (SuppressionMatch(supp->templ, frame->func) || 154 SuppressionMatch(supp->templ, frame->file))) { 155 DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ); 156 return true; 157 } 158 } 159 } 160 return false; 161} 162} // namespace __tsan 163