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_libc.h"
18 namespace __sanitizer
{
20 static const char *const kTypeStrings
[SuppressionTypeCount
] = {
21 "none", "race", "mutex", "thread", "signal", "leak", "called_from_lib"
24 bool TemplateMatch(char *templ
, const char *str
) {
25 if (str
== 0 || str
[0] == 0)
28 if (templ
&& templ
[0] == '^') {
32 bool asterisk
= false;
33 while (templ
&& templ
[0]) {
34 if (templ
[0] == '*') {
41 return str
[0] == 0 || asterisk
;
44 char *tpos
= (char*)internal_strchr(templ
, '*');
45 char *tpos1
= (char*)internal_strchr(templ
, '$');
46 if (tpos
== 0 || (tpos1
&& tpos1
< tpos
))
50 const char *str0
= str
;
51 const char *spos
= internal_strstr(str
, templ
);
52 str
= spos
+ internal_strlen(templ
);
55 tpos
[0] = tpos
== tpos1
? '$' : '*';
58 if (start
&& spos
!= str0
)
66 bool SuppressionContext::Match(const char *str
, SuppressionType type
,
70 for (i
= 0; i
< suppressions_
.size(); i
++)
71 if (type
== suppressions_
[i
].type
&&
72 TemplateMatch(suppressions_
[i
].templ
, str
))
74 if (i
== suppressions_
.size()) return false;
75 *s
= &suppressions_
[i
];
79 static const char *StripPrefix(const char *str
, const char *prefix
) {
80 while (str
&& *str
== *prefix
) {
89 void SuppressionContext::Parse(const char *str
) {
90 // Context must not mutate once Match has been called.
92 const char *line
= str
;
94 while (line
[0] == ' ' || line
[0] == '\t')
96 const char *end
= internal_strchr(line
, '\n');
98 end
= line
+ internal_strlen(line
);
99 if (line
!= end
&& line
[0] != '#') {
100 const char *end2
= end
;
101 while (line
!= end2
&& (end2
[-1] == ' ' || end2
[-1] == '\t'))
104 for (type
= 0; type
< SuppressionTypeCount
; type
++) {
105 const char *next_char
= StripPrefix(line
, kTypeStrings
[type
]);
106 if (next_char
&& *next_char
== ':') {
111 if (type
== SuppressionTypeCount
) {
112 Printf("%s: failed to parse suppressions\n", SanitizerToolName
);
116 s
.type
= static_cast<SuppressionType
>(type
);
117 s
.templ
= (char*)InternalAlloc(end2
- line
+ 1);
118 internal_memcpy(s
.templ
, line
, end2
- line
);
119 s
.templ
[end2
- line
] = 0;
122 suppressions_
.push_back(s
);
130 uptr
SuppressionContext::SuppressionCount() const {
131 return suppressions_
.size();
134 const Suppression
*SuppressionContext::SuppressionAt(uptr i
) const {
135 CHECK_LT(i
, suppressions_
.size());
136 return &suppressions_
[i
];
139 void SuppressionContext::GetMatched(
140 InternalMmapVector
<Suppression
*> *matched
) {
141 for (uptr i
= 0; i
< suppressions_
.size(); i
++)
142 if (suppressions_
[i
].hit_count
)
143 matched
->push_back(&suppressions_
[i
]);
146 const char *SuppressionTypeString(SuppressionType t
) {
147 CHECK(t
< SuppressionTypeCount
);
148 return kTypeStrings
[t
];
151 } // namespace __sanitizer