Daily bump.
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_suppressions.cc
blobab40598ae8ee4330e36c27bd775e7909667add75
1 //===-- sanitizer_suppressions.cc -----------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // Suppression parsing/matching code shared between TSan and LSan.
9 //
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)
28 return false;
29 bool start = false;
30 if (templ && templ[0] == '^') {
31 start = true;
32 templ++;
34 bool asterisk = false;
35 while (templ && templ[0]) {
36 if (templ[0] == '*') {
37 templ++;
38 start = false;
39 asterisk = true;
40 continue;
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;
65 return true;
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() {
77 if (suppression_ctx)
78 return;
79 suppression_ctx = new(placeholder) SuppressionContext;
80 if (common_flags()->suppressions[0] == '\0')
81 return;
82 char *suppressions_from_file;
83 uptr buffer_size;
84 uptr contents_size =
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);
90 Die();
92 suppression_ctx->Parse(suppressions_from_file);
95 bool SuppressionContext::Match(const char *str, SuppressionType type,
96 Suppression **s) {
97 can_parse_ = false;
98 uptr i;
99 for (i = 0; i < suppressions_.size(); i++)
100 if (type == suppressions_[i].type &&
101 TemplateMatch(suppressions_[i].templ, str))
102 break;
103 if (i == suppressions_.size()) return false;
104 *s = &suppressions_[i];
105 return true;
108 static const char *StripPrefix(const char *str, const char *prefix) {
109 while (str && *str == *prefix) {
110 str++;
111 prefix++;
113 if (!*prefix)
114 return str;
115 return 0;
118 void SuppressionContext::Parse(const char *str) {
119 // Context must not mutate once Match has been called.
120 CHECK(can_parse_);
121 const char *line = str;
122 while (line) {
123 while (line[0] == ' ' || line[0] == '\t')
124 line++;
125 const char *end = internal_strchr(line, '\n');
126 if (end == 0)
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'))
131 end2--;
132 int type;
133 for (type = 0; type < SuppressionTypeCount; type++) {
134 const char *next_char = StripPrefix(line, kTypeStrings[type]);
135 if (next_char && *next_char == ':') {
136 line = ++next_char;
137 break;
140 if (type == SuppressionTypeCount) {
141 Printf("%s: failed to parse suppressions\n", SanitizerToolName);
142 Die();
144 Suppression s;
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;
149 s.hit_count = 0;
150 s.weight = 0;
151 suppressions_.push_back(s);
153 if (end[0] == 0)
154 break;
155 line = end + 1;
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