1 //===-- sanitizer_suppressions.cc -----------------------------------------===//
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 // Suppression parsing/matching code shared between TSan and LSan.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "sanitizer_suppressions.h"
15
16 #include "sanitizer_allocator_internal.h"
17 #include "sanitizer_common.h"
18 #include "sanitizer_libc.h"
19
20 namespace __sanitizer {
21
22 static const char *const kTypeStrings[SuppressionTypeCount] = {
23 "none", "race", "mutex", "thread",
24 "signal", "leak", "called_from_lib", "deadlock"};
25
TemplateMatch(char * templ,const char * str)26 bool TemplateMatch(char *templ, const char *str) {
27 if (str == 0 || str[0] == 0)
28 return false;
29 bool start = false;
30 if (templ && templ[0] == '^') {
31 start = true;
32 templ++;
33 }
34 bool asterisk = false;
35 while (templ && templ[0]) {
36 if (templ[0] == '*') {
37 templ++;
38 start = false;
39 asterisk = true;
40 continue;
41 }
42 if (templ[0] == '$')
43 return str[0] == 0 || asterisk;
44 if (str[0] == 0)
45 return false;
46 char *tpos = (char*)internal_strchr(templ, '*');
47 char *tpos1 = (char*)internal_strchr(templ, '$');
48 if (tpos == 0 || (tpos1 && tpos1 < tpos))
49 tpos = tpos1;
50 if (tpos != 0)
51 tpos[0] = 0;
52 const char *str0 = str;
53 const char *spos = internal_strstr(str, templ);
54 str = spos + internal_strlen(templ);
55 templ = tpos;
56 if (tpos)
57 tpos[0] = tpos == tpos1 ? '$' : '*';
58 if (spos == 0)
59 return false;
60 if (start && spos != str0)
61 return false;
62 start = false;
63 asterisk = false;
64 }
65 return true;
66 }
67
Match(const char * str,SuppressionType type,Suppression ** s)68 bool SuppressionContext::Match(const char *str, SuppressionType type,
69 Suppression **s) {
70 can_parse_ = false;
71 uptr i;
72 for (i = 0; i < suppressions_.size(); i++)
73 if (type == suppressions_[i].type &&
74 TemplateMatch(suppressions_[i].templ, str))
75 break;
76 if (i == suppressions_.size()) return false;
77 *s = &suppressions_[i];
78 return true;
79 }
80
StripPrefix(const char * str,const char * prefix)81 static const char *StripPrefix(const char *str, const char *prefix) {
82 while (str && *str == *prefix) {
83 str++;
84 prefix++;
85 }
86 if (!*prefix)
87 return str;
88 return 0;
89 }
90
Parse(const char * str)91 void SuppressionContext::Parse(const char *str) {
92 // Context must not mutate once Match has been called.
93 CHECK(can_parse_);
94 const char *line = str;
95 while (line) {
96 while (line[0] == ' ' || line[0] == '\t')
97 line++;
98 const char *end = internal_strchr(line, '\n');
99 if (end == 0)
100 end = line + internal_strlen(line);
101 if (line != end && line[0] != '#') {
102 const char *end2 = end;
103 while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
104 end2--;
105 int type;
106 for (type = 0; type < SuppressionTypeCount; type++) {
107 const char *next_char = StripPrefix(line, kTypeStrings[type]);
108 if (next_char && *next_char == ':') {
109 line = ++next_char;
110 break;
111 }
112 }
113 if (type == SuppressionTypeCount) {
114 Printf("%s: failed to parse suppressions\n", SanitizerToolName);
115 Die();
116 }
117 Suppression s;
118 s.type = static_cast<SuppressionType>(type);
119 s.templ = (char*)InternalAlloc(end2 - line + 1);
120 internal_memcpy(s.templ, line, end2 - line);
121 s.templ[end2 - line] = 0;
122 s.hit_count = 0;
123 s.weight = 0;
124 suppressions_.push_back(s);
125 }
126 if (end[0] == 0)
127 break;
128 line = end + 1;
129 }
130 }
131
SuppressionCount() const132 uptr SuppressionContext::SuppressionCount() const {
133 return suppressions_.size();
134 }
135
SuppressionAt(uptr i) const136 const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
137 CHECK_LT(i, suppressions_.size());
138 return &suppressions_[i];
139 }
140
GetMatched(InternalMmapVector<Suppression * > * matched)141 void SuppressionContext::GetMatched(
142 InternalMmapVector<Suppression *> *matched) {
143 for (uptr i = 0; i < suppressions_.size(); i++)
144 if (suppressions_[i].hit_count)
145 matched->push_back(&suppressions_[i]);
146 }
147
SuppressionTypeString(SuppressionType t)148 const char *SuppressionTypeString(SuppressionType t) {
149 CHECK(t < SuppressionTypeCount);
150 return kTypeStrings[t];
151 }
152
153 } // namespace __sanitizer
154