1 //===-- tsan_suppressions.cc ----------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_common/sanitizer_common.h"
13 #include "sanitizer_common/sanitizer_libc.h"
14 #include "tsan_suppressions.h"
16 #include "tsan_flags.h"
17 #include "tsan_mman.h"
18 #include "tsan_platform.h"
20 // Can be overriden in frontend.
22 extern "C" const char *WEAK
__tsan_default_suppressions() {
29 static Suppression
*g_suppressions
;
31 static char *ReadFile(const char *filename
) {
32 if (filename
== 0 || filename
[0] == 0)
34 InternalScopedBuffer
<char> tmp(4*1024);
35 if (filename
[0] == '/' || GetPwd() == 0)
36 internal_snprintf(tmp
.data(), tmp
.size(), "%s", filename
);
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",
45 const uptr fsize
= internal_filesize(fd
);
46 if (fsize
== (uptr
)-1) {
47 Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
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",
62 bool SuppressionMatch(char *templ
, const char *str
) {
63 if (str
== 0 || str
[0] == 0)
67 while (templ
&& templ
[0]) {
68 if (templ
[0] == '*') {
74 tpos
= (char*)internal_strchr(templ
, '*');
77 spos
= internal_strstr(str
, templ
);
78 str
= spos
+ internal_strlen(templ
);
88 Suppression
*SuppressionParse(Suppression
*head
, const char* supp
) {
89 const char *line
= supp
;
91 while (line
[0] == ' ' || line
[0] == '\t')
93 const char *end
= internal_strchr(line
, '\n');
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'))
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;
117 Printf("ThreadSanitizer: failed to parse suppressions file\n");
120 Suppression
*s
= (Suppression
*)internal_alloc(MBlockSuppression
,
121 sizeof(Suppression
));
125 s
->templ
= (char*)internal_alloc(MBlockSuppression
, end2
- line
+ 1);
126 internal_memcpy(s
->templ
, line
, end2
- line
);
127 s
->templ
[end2
- line
] = 0;
136 void InitializeSuppressions() {
137 const char *supp
= ReadFile(flags()->suppressions
);
138 g_suppressions
= SuppressionParse(0, supp
);
140 supp
= __tsan_default_suppressions();
141 g_suppressions
= SuppressionParse(g_suppressions
, supp
);
145 uptr
IsSuppressed(ReportType typ
, const ReportStack
*stack
) {
146 if (g_suppressions
== 0 || stack
== 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
;
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
);
172 } // namespace __tsan