blob: f442fe1e0c29410cd4644ffd63a202273cdc3d1d [file] [log] [blame]
Alexey Samsonov603c4be2012-06-04 13:55:19 +00001//===-- tsan_suppressions.cc ----------------------------------------------===//
Kostya Serebryany7ac41482012-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 Samsonov0969bcf2012-06-18 08:44:30 +000014#include "sanitizer_common/sanitizer_common.h"
Alexey Samsonov7f9c5a22012-06-05 07:46:31 +000015#include "sanitizer_common/sanitizer_libc.h"
Kostya Serebryany7ac41482012-05-10 13:48:04 +000016#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;
Alexey Samsonov14c8bd72012-08-22 07:25:52 +000029 InternalScopedBuffer<char> tmp(4*1024);
Kostya Serebryany7ac41482012-05-10 13:48:04 +000030 if (filename[0] == '/')
Alexey Samsonov14c8bd72012-08-22 07:25:52 +000031 internal_snprintf(tmp, tmp.size(), "%s", filename);
Kostya Serebryany7ac41482012-05-10 13:48:04 +000032 else
Alexey Samsonov14c8bd72012-08-22 07:25:52 +000033 internal_snprintf(tmp, tmp.size(), "%s/%s", GetPwd(), filename);
Kostya Serebryany7ac41482012-05-10 13:48:04 +000034 fd_t fd = internal_open(tmp, false);
35 if (fd == kInvalidFd) {
Alexey Samsonov67a64dd2012-06-06 10:13:27 +000036 TsanPrintf("ThreadSanitizer: failed to open suppressions file '%s'\n",
Alexey Samsonov14c8bd72012-08-22 07:25:52 +000037 tmp.data());
Kostya Serebryany7ac41482012-05-10 13:48:04 +000038 Die();
39 }
40 const uptr fsize = internal_filesize(fd);
41 if (fsize == (uptr)-1) {
Alexey Samsonov67a64dd2012-06-06 10:13:27 +000042 TsanPrintf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
Alexey Samsonov14c8bd72012-08-22 07:25:52 +000043 tmp.data());
Kostya Serebryany7ac41482012-05-10 13:48:04 +000044 Die();
45 }
46 char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
47 if (fsize != internal_read(fd, buf, fsize)) {
Alexey Samsonov67a64dd2012-06-06 10:13:27 +000048 TsanPrintf("ThreadSanitizer: failed to read suppressions file '%s'\n",
Alexey Samsonov14c8bd72012-08-22 07:25:52 +000049 tmp.data());
Kostya Serebryany7ac41482012-05-10 13:48:04 +000050 Die();
51 }
52 internal_close(fd);
53 buf[fsize] = 0;
54 return buf;
55}
56
57bool SuppressionMatch(char *templ, const char *str) {
Dmitry Vyukov20f60c52012-05-31 13:18:11 +000058 if (str == 0 || str[0] == 0)
59 return false;
Kostya Serebryany7ac41482012-05-10 13:48:04 +000060 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;
Dmitry Vyukovd51a1a12012-06-27 21:00:23 +000072 spos = internal_strstr(str, templ);
Kostya Serebryany7ac41482012-05-10 13:48:04 +000073 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;
Dmitry Vyukovd51a1a12012-06-27 21:00:23 +000097 if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) {
Kostya Serebryany7ac41482012-05-10 13:48:04 +000098 stype = SuppressionRace;
99 line += sizeof("race:") - 1;
Dmitry Vyukovd51a1a12012-06-27 21:00:23 +0000100 } else if (0 == internal_strncmp(line, "thread:",
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000101 sizeof("thread:") - 1)) {
102 stype = SuppressionThread;
103 line += sizeof("thread:") - 1;
Dmitry Vyukovd51a1a12012-06-27 21:00:23 +0000104 } else if (0 == internal_strncmp(line, "mutex:",
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000105 sizeof("mutex:") - 1)) {
106 stype = SuppressionMutex;
107 line += sizeof("mutex:") - 1;
Dmitry Vyukovd51a1a12012-06-27 21:00:23 +0000108 } else if (0 == internal_strncmp(line, "signal:",
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000109 sizeof("signal:") - 1)) {
110 stype = SuppressionSignal;
111 line += sizeof("signal:") - 1;
112 } else {
Alexey Samsonov67a64dd2012-06-06 10:13:27 +0000113 TsanPrintf("ThreadSanitizer: failed to parse suppressions file\n");
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000114 Die();
115 }
116 Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
117 sizeof(Suppression));
118 s->next = head;
119 head = s;
120 s->type = stype;
Dmitry Vyukov20f60c52012-05-31 13:18:11 +0000121 s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
Dmitry Vyukovd51a1a12012-06-27 21:00:23 +0000122 internal_memcpy(s->templ, line, end2 - line);
Dmitry Vyukov20f60c52012-05-31 13:18:11 +0000123 s->templ[end2 - line] = 0;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000124 }
125 if (end[0] == 0)
126 break;
127 line = end + 1;
128 }
129 return head;
130}
131
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000132void InitializeSuppressions() {
133 char *supp = ReadFile(flags()->suppressions);
134 g_suppressions = SuppressionParse(supp);
135}
136
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000137bool 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) {
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000152 for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
Dmitry Vyukova13749b2012-05-31 14:24:10 +0000153 if (stype == supp->type &&
154 (SuppressionMatch(supp->templ, frame->func) ||
155 SuppressionMatch(supp->templ, frame->file))) {
Dmitry Vyukov20f60c52012-05-31 13:18:11 +0000156 DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000157 return true;
158 }
159 }
160 }
161 return false;
162}
163} // namespace __tsan