libsanitizer merge from upstream r175733
[official-gcc.git] / libsanitizer / tsan / tsan_suppressions.cc
blob8ee8de7c27887d09c8d4a4090a784eb4e247c0dd
1 //===-- tsan_suppressions.cc ----------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
9 //
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_common/sanitizer_common.h"
13 #include "sanitizer_common/sanitizer_libc.h"
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"
20 // Can be overriden in frontend.
21 #ifndef TSAN_GO
22 extern "C" const char *WEAK __tsan_default_suppressions() {
23 return 0;
25 #endif
27 namespace __tsan {
29 static Suppression *g_suppressions;
31 static char *ReadFile(const char *filename) {
32 if (filename == 0 || filename[0] == 0)
33 return 0;
34 InternalScopedBuffer<char> tmp(4*1024);
35 if (filename[0] == '/' || GetPwd() == 0)
36 internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
37 else
38 internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
39 fd_t fd = OpenFile(tmp.data(), false);
40 if (fd == kInvalidFd) {
41 Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
42 tmp.data());
43 Die();
45 const uptr fsize = internal_filesize(fd);
46 if (fsize == (uptr)-1) {
47 Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
48 tmp.data());
49 Die();
51 char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
52 if (fsize != internal_read(fd, buf, fsize)) {
53 Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
54 tmp.data());
55 Die();
57 internal_close(fd);
58 buf[fsize] = 0;
59 return buf;
62 bool SuppressionMatch(char *templ, const char *str) {
63 if (str == 0 || str[0] == 0)
64 return false;
65 char *tpos;
66 const char *spos;
67 while (templ && templ[0]) {
68 if (templ[0] == '*') {
69 templ++;
70 continue;
72 if (str[0] == 0)
73 return false;
74 tpos = (char*)internal_strchr(templ, '*');
75 if (tpos != 0)
76 tpos[0] = 0;
77 spos = internal_strstr(str, templ);
78 str = spos + internal_strlen(templ);
79 templ = tpos;
80 if (tpos)
81 tpos[0] = '*';
82 if (spos == 0)
83 return false;
85 return true;
88 Suppression *SuppressionParse(Suppression *head, const char* supp) {
89 const char *line = supp;
90 while (line) {
91 while (line[0] == ' ' || line[0] == '\t')
92 line++;
93 const char *end = internal_strchr(line, '\n');
94 if (end == 0)
95 end = line + internal_strlen(line);
96 if (line != end && line[0] != '#') {
97 const char *end2 = end;
98 while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
99 end2--;
100 SuppressionType stype;
101 if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) {
102 stype = SuppressionRace;
103 line += sizeof("race:") - 1;
104 } else if (0 == internal_strncmp(line, "thread:",
105 sizeof("thread:") - 1)) {
106 stype = SuppressionThread;
107 line += sizeof("thread:") - 1;
108 } else if (0 == internal_strncmp(line, "mutex:",
109 sizeof("mutex:") - 1)) {
110 stype = SuppressionMutex;
111 line += sizeof("mutex:") - 1;
112 } else if (0 == internal_strncmp(line, "signal:",
113 sizeof("signal:") - 1)) {
114 stype = SuppressionSignal;
115 line += sizeof("signal:") - 1;
116 } else {
117 Printf("ThreadSanitizer: failed to parse suppressions file\n");
118 Die();
120 Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
121 sizeof(Suppression));
122 s->next = head;
123 head = s;
124 s->type = stype;
125 s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
126 internal_memcpy(s->templ, line, end2 - line);
127 s->templ[end2 - line] = 0;
129 if (end[0] == 0)
130 break;
131 line = end + 1;
133 return head;
136 void InitializeSuppressions() {
137 const char *supp = ReadFile(flags()->suppressions);
138 g_suppressions = SuppressionParse(0, supp);
139 #ifndef TSAN_GO
140 supp = __tsan_default_suppressions();
141 g_suppressions = SuppressionParse(g_suppressions, supp);
142 #endif
145 uptr IsSuppressed(ReportType typ, const ReportStack *stack) {
146 if (g_suppressions == 0 || stack == 0)
147 return 0;
148 SuppressionType stype;
149 if (typ == ReportTypeRace)
150 stype = SuppressionRace;
151 else if (typ == ReportTypeThreadLeak)
152 stype = SuppressionThread;
153 else if (typ == ReportTypeMutexDestroyLocked)
154 stype = SuppressionMutex;
155 else if (typ == ReportTypeSignalUnsafe)
156 stype = SuppressionSignal;
157 else
158 return 0;
159 for (const ReportStack *frame = stack; frame; frame = frame->next) {
160 for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
161 if (stype == supp->type &&
162 (SuppressionMatch(supp->templ, frame->func) ||
163 SuppressionMatch(supp->templ, frame->file) ||
164 SuppressionMatch(supp->templ, frame->module))) {
165 DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
166 return frame->pc;
170 return 0;
172 } // namespace __tsan