tsan_suppressions.cc revision a13749bd7b3629a3498e765960729a8ade5db7cf
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 if (str == 0 || str[0] == 0) 57 return false; 58 char *tpos; 59 const char *spos; 60 while (templ && templ[0]) { 61 if (templ[0] == '*') { 62 templ++; 63 continue; 64 } 65 if (str[0] == 0) 66 return false; 67 tpos = (char*)internal_strchr(templ, '*'); 68 if (tpos != 0) 69 tpos[0] = 0; 70 spos = internal_strstr(str, templ); 71 str = spos + internal_strlen(templ); 72 templ = tpos; 73 if (tpos) 74 tpos[0] = '*'; 75 if (spos == 0) 76 return false; 77 } 78 return true; 79} 80 81Suppression *SuppressionParse(const char* supp) { 82 Suppression *head = 0; 83 const char *line = supp; 84 while (line) { 85 while (line[0] == ' ' || line[0] == '\t') 86 line++; 87 const char *end = internal_strchr(line, '\n'); 88 if (end == 0) 89 end = line + internal_strlen(line); 90 if (line != end && line[0] != '#') { 91 const char *end2 = end; 92 while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t')) 93 end2--; 94 SuppressionType stype; 95 if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) { 96 stype = SuppressionRace; 97 line += sizeof("race:") - 1; 98 } else if (0 == internal_strncmp(line, "thread:", 99 sizeof("thread:") - 1)) { 100 stype = SuppressionThread; 101 line += sizeof("thread:") - 1; 102 } else if (0 == internal_strncmp(line, "mutex:", 103 sizeof("mutex:") - 1)) { 104 stype = SuppressionMutex; 105 line += sizeof("mutex:") - 1; 106 } else if (0 == internal_strncmp(line, "signal:", 107 sizeof("signal:") - 1)) { 108 stype = SuppressionSignal; 109 line += sizeof("signal:") - 1; 110 } else { 111 Printf("ThreadSanitizer: failed to parse suppressions file\n"); 112 Die(); 113 } 114 Suppression *s = (Suppression*)internal_alloc(MBlockSuppression, 115 sizeof(Suppression)); 116 s->next = head; 117 head = s; 118 s->type = stype; 119 s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1); 120 internal_memcpy(s->templ, line, end2 - line); 121 s->templ[end2 - line] = 0; 122 } 123 if (end[0] == 0) 124 break; 125 line = end + 1; 126 } 127 return head; 128} 129 130void InitializeSuppressions() { 131 char *supp = ReadFile(flags()->suppressions); 132 g_suppressions = SuppressionParse(supp); 133} 134 135bool IsSuppressed(ReportType typ, const ReportStack *stack) { 136 if (g_suppressions == 0 || stack == 0) 137 return false; 138 SuppressionType stype; 139 if (typ == ReportTypeRace) 140 stype = SuppressionRace; 141 else if (typ == ReportTypeThreadLeak) 142 stype = SuppressionThread; 143 else if (typ == ReportTypeMutexDestroyLocked) 144 stype = SuppressionMutex; 145 else if (typ == ReportTypeSignalUnsafe) 146 stype = SuppressionSignal; 147 else 148 return false; 149 for (const ReportStack *frame = stack; frame; frame = frame->next) { 150 for (Suppression *supp = g_suppressions; supp; supp = supp->next) { 151 if (stype == supp->type && 152 (SuppressionMatch(supp->templ, frame->func) || 153 SuppressionMatch(supp->templ, frame->file))) { 154 DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ); 155 return true; 156 } 157 } 158 } 159 return false; 160} 161} // namespace __tsan 162