• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
22 // Can be overriden in frontend.
23 #ifndef TSAN_GO
__tsan_default_suppressions()24 extern "C" const char *WEAK __tsan_default_suppressions() {
25   return 0;
26 }
27 #endif
28 
29 namespace __tsan {
30 
31 static Suppression *g_suppressions;
32 
ReadFile(const char * filename)33 static char *ReadFile(const char *filename) {
34   if (filename == 0 || filename[0] == 0)
35     return 0;
36   InternalScopedBuffer<char> tmp(4*1024);
37   if (filename[0] == '/' || GetPwd() == 0)
38     internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
39   else
40     internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
41   fd_t fd = OpenFile(tmp.data(), false);
42   if (fd == kInvalidFd) {
43     Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
44                tmp.data());
45     Die();
46   }
47   const uptr fsize = internal_filesize(fd);
48   if (fsize == (uptr)-1) {
49     Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
50                tmp.data());
51     Die();
52   }
53   char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
54   if (fsize != internal_read(fd, buf, fsize)) {
55     Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
56                tmp.data());
57     Die();
58   }
59   internal_close(fd);
60   buf[fsize] = 0;
61   return buf;
62 }
63 
SuppressionMatch(char * templ,const char * str)64 bool SuppressionMatch(char *templ, const char *str) {
65   if (str == 0 || str[0] == 0)
66     return false;
67   char *tpos;
68   const char *spos;
69   while (templ && templ[0]) {
70     if (templ[0] == '*') {
71       templ++;
72       continue;
73     }
74     if (str[0] == 0)
75       return false;
76     tpos = (char*)internal_strchr(templ, '*');
77     if (tpos != 0)
78       tpos[0] = 0;
79     spos = internal_strstr(str, templ);
80     str = spos + internal_strlen(templ);
81     templ = tpos;
82     if (tpos)
83       tpos[0] = '*';
84     if (spos == 0)
85       return false;
86   }
87   return true;
88 }
89 
SuppressionParse(Suppression * head,const char * supp)90 Suppression *SuppressionParse(Suppression *head, const char* supp) {
91   const char *line = supp;
92   while (line) {
93     while (line[0] == ' ' || line[0] == '\t')
94       line++;
95     const char *end = internal_strchr(line, '\n');
96     if (end == 0)
97       end = line + internal_strlen(line);
98     if (line != end && line[0] != '#') {
99       const char *end2 = end;
100       while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
101         end2--;
102       SuppressionType stype;
103       if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) {
104         stype = SuppressionRace;
105         line += sizeof("race:") - 1;
106       } else if (0 == internal_strncmp(line, "thread:",
107           sizeof("thread:") - 1)) {
108         stype = SuppressionThread;
109         line += sizeof("thread:") - 1;
110       } else if (0 == internal_strncmp(line, "mutex:",
111           sizeof("mutex:") - 1)) {
112         stype = SuppressionMutex;
113         line += sizeof("mutex:") - 1;
114       } else if (0 == internal_strncmp(line, "signal:",
115           sizeof("signal:") - 1)) {
116         stype = SuppressionSignal;
117         line += sizeof("signal:") - 1;
118       } else {
119         Printf("ThreadSanitizer: failed to parse suppressions file\n");
120         Die();
121       }
122       Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
123           sizeof(Suppression));
124       s->next = head;
125       head = s;
126       s->type = stype;
127       s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
128       internal_memcpy(s->templ, line, end2 - line);
129       s->templ[end2 - line] = 0;
130     }
131     if (end[0] == 0)
132       break;
133     line = end + 1;
134   }
135   return head;
136 }
137 
InitializeSuppressions()138 void InitializeSuppressions() {
139   const char *supp = ReadFile(flags()->suppressions);
140   g_suppressions = SuppressionParse(0, supp);
141 #ifndef TSAN_GO
142   supp = __tsan_default_suppressions();
143   g_suppressions = SuppressionParse(g_suppressions, supp);
144 #endif
145 }
146 
IsSuppressed(ReportType typ,const ReportStack * stack)147 uptr IsSuppressed(ReportType typ, const ReportStack *stack) {
148   if (g_suppressions == 0 || stack == 0)
149     return 0;
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 0;
161   for (const ReportStack *frame = stack; frame; frame = frame->next) {
162     for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
163       if (stype == supp->type &&
164           (SuppressionMatch(supp->templ, frame->func) ||
165            SuppressionMatch(supp->templ, frame->file) ||
166            SuppressionMatch(supp->templ, frame->module))) {
167         DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
168         return frame->pc;
169       }
170     }
171   }
172   return 0;
173 }
174 }  // namespace __tsan
175