1 //===-- sanitizer_suppressions.cc -----------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Suppression parsing/matching code shared between TSan and LSan.
12 //===----------------------------------------------------------------------===//
14 #include "sanitizer_suppressions.h"
16 #include "sanitizer_allocator_internal.h"
17 #include "sanitizer_common.h"
18 #include "sanitizer_flags.h"
19 #include "sanitizer_libc.h"
20 #include "sanitizer_placement_new.h"
22 namespace __sanitizer {
24 static const char *const kTypeStrings[SuppressionTypeCount] = {
25 "none", "race", "mutex", "thread", "signal", "leak", "called_from_lib",
26 "deadlock", "vptr_check", "interceptor_name", "interceptor_via_fun",
27 "interceptor_via_lib"};
29 bool TemplateMatch(char *templ, const char *str) {
30 if (str == 0 || str[0] == 0)
33 if (templ && templ[0] == '^') {
37 bool asterisk = false;
38 while (templ && templ[0]) {
39 if (templ[0] == '*') {
46 return str[0] == 0 || asterisk;
49 char *tpos = (char*)internal_strchr(templ, '*');
50 char *tpos1 = (char*)internal_strchr(templ, '$');
51 if (tpos == 0 || (tpos1 && tpos1 < tpos))
55 const char *str0 = str;
56 const char *spos = internal_strstr(str, templ);
57 str = spos + internal_strlen(templ);
60 tpos[0] = tpos == tpos1 ? '$' : '*';
63 if (start && spos != str0)
71 ALIGNED(64) static char placeholder[sizeof(SuppressionContext)];
72 static SuppressionContext *suppression_ctx = 0;
74 SuppressionContext::SuppressionContext() : suppressions_(1), can_parse_(true) {
75 internal_memset(has_suppresson_type_, 0, sizeof(has_suppresson_type_));
78 SuppressionContext *SuppressionContext::Get() {
79 CHECK(suppression_ctx);
80 return suppression_ctx;
83 void SuppressionContext::InitIfNecessary() {
86 suppression_ctx = new(placeholder) SuppressionContext;
87 if (common_flags()->suppressions[0] == '\0')
89 char *suppressions_from_file;
92 ReadFileToBuffer(common_flags()->suppressions, &suppressions_from_file,
93 &buffer_size, 1 << 26 /* max_len */);
94 if (contents_size == 0) {
95 Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
96 common_flags()->suppressions);
99 suppression_ctx->Parse(suppressions_from_file);
102 bool SuppressionContext::Match(const char *str, SuppressionType type,
104 if (!has_suppresson_type_[type])
108 for (i = 0; i < suppressions_.size(); i++)
109 if (type == suppressions_[i].type &&
110 TemplateMatch(suppressions_[i].templ, str))
112 if (i == suppressions_.size()) return false;
113 *s = &suppressions_[i];
117 static const char *StripPrefix(const char *str, const char *prefix) {
118 while (str && *str == *prefix) {
127 void SuppressionContext::Parse(const char *str) {
128 // Context must not mutate once Match has been called.
130 const char *line = str;
132 while (line[0] == ' ' || line[0] == '\t')
134 const char *end = internal_strchr(line, '\n');
136 end = line + internal_strlen(line);
137 if (line != end && line[0] != '#') {
138 const char *end2 = end;
139 while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
142 for (type = 0; type < SuppressionTypeCount; type++) {
143 const char *next_char = StripPrefix(line, kTypeStrings[type]);
144 if (next_char && *next_char == ':') {
149 if (type == SuppressionTypeCount) {
150 Printf("%s: failed to parse suppressions\n", SanitizerToolName);
154 s.type = static_cast<SuppressionType>(type);
155 s.templ = (char*)InternalAlloc(end2 - line + 1);
156 internal_memcpy(s.templ, line, end2 - line);
157 s.templ[end2 - line] = 0;
160 suppressions_.push_back(s);
161 has_suppresson_type_[s.type] = true;
169 uptr SuppressionContext::SuppressionCount() const {
170 return suppressions_.size();
173 bool SuppressionContext::HasSuppressionType(SuppressionType type) const {
174 return has_suppresson_type_[type];
177 const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
178 CHECK_LT(i, suppressions_.size());
179 return &suppressions_[i];
182 void SuppressionContext::GetMatched(
183 InternalMmapVector<Suppression *> *matched) {
184 for (uptr i = 0; i < suppressions_.size(); i++)
185 if (suppressions_[i].hit_count)
186 matched->push_back(&suppressions_[i]);
189 const char *SuppressionTypeString(SuppressionType t) {
190 CHECK(t < SuppressionTypeCount);
191 return kTypeStrings[t];
194 } // namespace __sanitizer