blob: 2c7c318a13c32b3e06b5a419bff56e553b808aa4 [file] [log] [blame]
Kostya Serebryany4ad375f2012-05-10 13:48:04 +00001//===-- 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) {
Dmitry Vyukovd6ffccd2012-05-31 13:18:11 +000056 if (str == 0 || str[0] == 0)
57 return false;
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000058 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;
Dmitry Vyukovd6ffccd2012-05-31 13:18:11 +0000119 s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
120 internal_memcpy(s->templ, line, end2 - line);
121 s->templ[end2 - line] = 0;
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000122 }
123 if (end[0] == 0)
124 break;
125 line = end + 1;
126 }
127 return head;
128}
129
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000130void InitializeSuppressions() {
131 char *supp = ReadFile(flags()->suppressions);
132 g_suppressions = SuppressionParse(supp);
133}
134
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000135bool 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) {
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000150 for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
Dmitry Vyukovd6ffccd2012-05-31 13:18:11 +0000151 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);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000155 return true;
156 }
157 }
158 }
159 return false;
160}
161} // namespace __tsan