blob: 613ff0320211d3513535e8573ba897cd2d0b8479 [file] [log] [blame]
Alexey Samsonov3b2f9f42012-06-04 13:55:19 +00001//===-- tsan_suppressions.cc ----------------------------------------------===//
Kostya Serebryany4ad375f2012-05-10 13:48:04 +00002//
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
Alexey Samsonov298dd7c2012-06-05 07:46:31 +000014#include "sanitizer_common/sanitizer_libc.h"
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000015#include "tsan_suppressions.h"
16#include "tsan_rtl.h"
17#include "tsan_flags.h"
18#include "tsan_mman.h"
19#include "tsan_platform.h"
20
21namespace __tsan {
22
23static Suppression *g_suppressions;
24
25static char *ReadFile(const char *filename) {
26 if (filename == 0 || filename[0] == 0)
27 return 0;
28 InternalScopedBuf<char> tmp(4*1024);
29 if (filename[0] == '/')
Alexey Samsonovac4c2902012-06-06 10:13:27 +000030 SNPrintf(tmp, tmp.Size(), "%s", filename);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000031 else
Alexey Samsonovac4c2902012-06-06 10:13:27 +000032 SNPrintf(tmp, tmp.Size(), "%s/%s", internal_getpwd(), filename);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000033 fd_t fd = internal_open(tmp, false);
34 if (fd == kInvalidFd) {
Alexey Samsonovac4c2902012-06-06 10:13:27 +000035 TsanPrintf("ThreadSanitizer: failed to open suppressions file '%s'\n",
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000036 tmp.Ptr());
37 Die();
38 }
39 const uptr fsize = internal_filesize(fd);
40 if (fsize == (uptr)-1) {
Alexey Samsonovac4c2902012-06-06 10:13:27 +000041 TsanPrintf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000042 tmp.Ptr());
43 Die();
44 }
45 char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
46 if (fsize != internal_read(fd, buf, fsize)) {
Alexey Samsonovac4c2902012-06-06 10:13:27 +000047 TsanPrintf("ThreadSanitizer: failed to read suppressions file '%s'\n",
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000048 tmp.Ptr());
49 Die();
50 }
51 internal_close(fd);
52 buf[fsize] = 0;
53 return buf;
54}
55
56bool SuppressionMatch(char *templ, const char *str) {
Dmitry Vyukovd6ffccd2012-05-31 13:18:11 +000057 if (str == 0 || str[0] == 0)
58 return false;
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000059 char *tpos;
60 const char *spos;
61 while (templ && templ[0]) {
62 if (templ[0] == '*') {
63 templ++;
64 continue;
65 }
66 if (str[0] == 0)
67 return false;
68 tpos = (char*)internal_strchr(templ, '*');
69 if (tpos != 0)
70 tpos[0] = 0;
Alexey Samsonov3efd6fc2012-06-15 12:24:07 +000071 spos = REAL(strstr)(str, templ);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000072 str = spos + internal_strlen(templ);
73 templ = tpos;
74 if (tpos)
75 tpos[0] = '*';
76 if (spos == 0)
77 return false;
78 }
79 return true;
80}
81
82Suppression *SuppressionParse(const char* supp) {
83 Suppression *head = 0;
84 const char *line = supp;
85 while (line) {
86 while (line[0] == ' ' || line[0] == '\t')
87 line++;
88 const char *end = internal_strchr(line, '\n');
89 if (end == 0)
90 end = line + internal_strlen(line);
91 if (line != end && line[0] != '#') {
92 const char *end2 = end;
93 while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
94 end2--;
95 SuppressionType stype;
Alexey Samsonov3efd6fc2012-06-15 12:24:07 +000096 if (0 == REAL(strncmp)(line, "race:", sizeof("race:") - 1)) {
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000097 stype = SuppressionRace;
98 line += sizeof("race:") - 1;
Alexey Samsonov3efd6fc2012-06-15 12:24:07 +000099 } else if (0 == REAL(strncmp)(line, "thread:",
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000100 sizeof("thread:") - 1)) {
101 stype = SuppressionThread;
102 line += sizeof("thread:") - 1;
Alexey Samsonov3efd6fc2012-06-15 12:24:07 +0000103 } else if (0 == REAL(strncmp)(line, "mutex:",
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000104 sizeof("mutex:") - 1)) {
105 stype = SuppressionMutex;
106 line += sizeof("mutex:") - 1;
Alexey Samsonov3efd6fc2012-06-15 12:24:07 +0000107 } else if (0 == REAL(strncmp)(line, "signal:",
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000108 sizeof("signal:") - 1)) {
109 stype = SuppressionSignal;
110 line += sizeof("signal:") - 1;
111 } else {
Alexey Samsonovac4c2902012-06-06 10:13:27 +0000112 TsanPrintf("ThreadSanitizer: failed to parse suppressions file\n");
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000113 Die();
114 }
115 Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
116 sizeof(Suppression));
117 s->next = head;
118 head = s;
119 s->type = stype;
Dmitry Vyukovd6ffccd2012-05-31 13:18:11 +0000120 s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
Alexey Samsonov3efd6fc2012-06-15 12:24:07 +0000121 REAL(memcpy)(s->templ, line, end2 - line);
Dmitry Vyukovd6ffccd2012-05-31 13:18:11 +0000122 s->templ[end2 - line] = 0;
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000123 }
124 if (end[0] == 0)
125 break;
126 line = end + 1;
127 }
128 return head;
129}
130
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000131void InitializeSuppressions() {
132 char *supp = ReadFile(flags()->suppressions);
133 g_suppressions = SuppressionParse(supp);
134}
135
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000136bool IsSuppressed(ReportType typ, const ReportStack *stack) {
137 if (g_suppressions == 0 || stack == 0)
138 return false;
139 SuppressionType stype;
140 if (typ == ReportTypeRace)
141 stype = SuppressionRace;
142 else if (typ == ReportTypeThreadLeak)
143 stype = SuppressionThread;
144 else if (typ == ReportTypeMutexDestroyLocked)
145 stype = SuppressionMutex;
146 else if (typ == ReportTypeSignalUnsafe)
147 stype = SuppressionSignal;
148 else
149 return false;
150 for (const ReportStack *frame = stack; frame; frame = frame->next) {
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000151 for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
Dmitry Vyukov6f448702012-05-31 14:24:10 +0000152 if (stype == supp->type &&
153 (SuppressionMatch(supp->templ, frame->func) ||
154 SuppressionMatch(supp->templ, frame->file))) {
Dmitry Vyukovd6ffccd2012-05-31 13:18:11 +0000155 DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000156 return true;
157 }
158 }
159 }
160 return false;
161}
162} // namespace __tsan