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