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