1 //===-- sanitizer_suppressions.cc -----------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // Suppression parsing/matching code shared between TSan and LSan.
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_suppressions.h"
14 #include "sanitizer_allocator_internal.h"
15 #include "sanitizer_common.h"
16 #include "sanitizer_flags.h"
17 #include "sanitizer_libc.h"
18 #include "sanitizer_placement_new.h"
20 namespace __sanitizer
{
22 static const char *const kTypeStrings
[SuppressionTypeCount
] = {
23 "none", "race", "mutex", "thread", "signal",
24 "leak", "called_from_lib", "deadlock", "vptr_check"};
26 bool TemplateMatch(char *templ
, const char *str
) {
27 if (str
== 0 || str
[0] == 0)
30 if (templ
&& templ
[0] == '^') {
34 bool asterisk
= false;
35 while (templ
&& templ
[0]) {
36 if (templ
[0] == '*') {
43 return str
[0] == 0 || asterisk
;
46 char *tpos
= (char*)internal_strchr(templ
, '*');
47 char *tpos1
= (char*)internal_strchr(templ
, '$');
48 if (tpos
== 0 || (tpos1
&& tpos1
< tpos
))
52 const char *str0
= str
;
53 const char *spos
= internal_strstr(str
, templ
);
54 str
= spos
+ internal_strlen(templ
);
57 tpos
[0] = tpos
== tpos1
? '$' : '*';
60 if (start
&& spos
!= str0
)
68 ALIGNED(64) static char placeholder
[sizeof(SuppressionContext
)];
69 static SuppressionContext
*suppression_ctx
= 0;
71 SuppressionContext
*SuppressionContext::Get() {
72 CHECK(suppression_ctx
);
73 return suppression_ctx
;
76 void SuppressionContext::InitIfNecessary() {
79 suppression_ctx
= new(placeholder
) SuppressionContext
;
80 if (common_flags()->suppressions
[0] == '\0')
82 char *suppressions_from_file
;
85 ReadFileToBuffer(common_flags()->suppressions
, &suppressions_from_file
,
86 &buffer_size
, 1 << 26 /* max_len */);
87 if (contents_size
== 0) {
88 Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName
,
89 common_flags()->suppressions
);
92 suppression_ctx
->Parse(suppressions_from_file
);
95 bool SuppressionContext::Match(const char *str
, SuppressionType type
,
99 for (i
= 0; i
< suppressions_
.size(); i
++)
100 if (type
== suppressions_
[i
].type
&&
101 TemplateMatch(suppressions_
[i
].templ
, str
))
103 if (i
== suppressions_
.size()) return false;
104 *s
= &suppressions_
[i
];
108 static const char *StripPrefix(const char *str
, const char *prefix
) {
109 while (str
&& *str
== *prefix
) {
118 void SuppressionContext::Parse(const char *str
) {
119 // Context must not mutate once Match has been called.
121 const char *line
= str
;
123 while (line
[0] == ' ' || line
[0] == '\t')
125 const char *end
= internal_strchr(line
, '\n');
127 end
= line
+ internal_strlen(line
);
128 if (line
!= end
&& line
[0] != '#') {
129 const char *end2
= end
;
130 while (line
!= end2
&& (end2
[-1] == ' ' || end2
[-1] == '\t'))
133 for (type
= 0; type
< SuppressionTypeCount
; type
++) {
134 const char *next_char
= StripPrefix(line
, kTypeStrings
[type
]);
135 if (next_char
&& *next_char
== ':') {
140 if (type
== SuppressionTypeCount
) {
141 Printf("%s: failed to parse suppressions\n", SanitizerToolName
);
145 s
.type
= static_cast<SuppressionType
>(type
);
146 s
.templ
= (char*)InternalAlloc(end2
- line
+ 1);
147 internal_memcpy(s
.templ
, line
, end2
- line
);
148 s
.templ
[end2
- line
] = 0;
151 suppressions_
.push_back(s
);
159 uptr
SuppressionContext::SuppressionCount() const {
160 return suppressions_
.size();
163 const Suppression
*SuppressionContext::SuppressionAt(uptr i
) const {
164 CHECK_LT(i
, suppressions_
.size());
165 return &suppressions_
[i
];
168 void SuppressionContext::GetMatched(
169 InternalMmapVector
<Suppression
*> *matched
) {
170 for (uptr i
= 0; i
< suppressions_
.size(); i
++)
171 if (suppressions_
[i
].hit_count
)
172 matched
->push_back(&suppressions_
[i
]);
175 const char *SuppressionTypeString(SuppressionType t
) {
176 CHECK(t
< SuppressionTypeCount
);
177 return kTypeStrings
[t
];
180 } // namespace __sanitizer