]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc
Merge latest (commit c8c1b3a77934768c7f7a4a9c10140c8bec529059) files
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / sanitizer_common / sanitizer_suppressions.cc
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_flags.h"
19 #include "sanitizer_libc.h"
20 #include "sanitizer_placement_new.h"
21
22 namespace __sanitizer {
23
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"};
28
29 bool TemplateMatch(char *templ, const char *str) {
30   if (str == 0 || str[0] == 0)
31     return false;
32   bool start = false;
33   if (templ && templ[0] == '^') {
34     start = true;
35     templ++;
36   }
37   bool asterisk = false;
38   while (templ && templ[0]) {
39     if (templ[0] == '*') {
40       templ++;
41       start = false;
42       asterisk = true;
43       continue;
44     }
45     if (templ[0] == '$')
46       return str[0] == 0 || asterisk;
47     if (str[0] == 0)
48       return false;
49     char *tpos = (char*)internal_strchr(templ, '*');
50     char *tpos1 = (char*)internal_strchr(templ, '$');
51     if (tpos == 0 || (tpos1 && tpos1 < tpos))
52       tpos = tpos1;
53     if (tpos != 0)
54       tpos[0] = 0;
55     const char *str0 = str;
56     const char *spos = internal_strstr(str, templ);
57     str = spos + internal_strlen(templ);
58     templ = tpos;
59     if (tpos)
60       tpos[0] = tpos == tpos1 ? '$' : '*';
61     if (spos == 0)
62       return false;
63     if (start && spos != str0)
64       return false;
65     start = false;
66     asterisk = false;
67   }
68   return true;
69 }
70
71 ALIGNED(64) static char placeholder[sizeof(SuppressionContext)];
72 static SuppressionContext *suppression_ctx = 0;
73
74 SuppressionContext::SuppressionContext() : suppressions_(1), can_parse_(true) {
75   internal_memset(has_suppresson_type_, 0, sizeof(has_suppresson_type_));
76 }
77
78 SuppressionContext *SuppressionContext::Get() {
79   CHECK(suppression_ctx);
80   return suppression_ctx;
81 }
82
83 void SuppressionContext::InitIfNecessary() {
84   if (suppression_ctx)
85     return;
86   suppression_ctx = new(placeholder) SuppressionContext;
87   if (common_flags()->suppressions[0] == '\0')
88     return;
89   char *suppressions_from_file;
90   uptr buffer_size;
91   uptr contents_size =
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);
97     Die();
98   }
99   suppression_ctx->Parse(suppressions_from_file);
100 }
101
102 bool SuppressionContext::Match(const char *str, SuppressionType type,
103                                Suppression **s) {
104   if (!has_suppresson_type_[type])
105     return false;
106   can_parse_ = false;
107   uptr i;
108   for (i = 0; i < suppressions_.size(); i++)
109     if (type == suppressions_[i].type &&
110         TemplateMatch(suppressions_[i].templ, str))
111       break;
112   if (i == suppressions_.size()) return false;
113   *s = &suppressions_[i];
114   return true;
115 }
116
117 static const char *StripPrefix(const char *str, const char *prefix) {
118   while (str && *str == *prefix) {
119     str++;
120     prefix++;
121   }
122   if (!*prefix)
123     return str;
124   return 0;
125 }
126
127 void SuppressionContext::Parse(const char *str) {
128   // Context must not mutate once Match has been called.
129   CHECK(can_parse_);
130   const char *line = str;
131   while (line) {
132     while (line[0] == ' ' || line[0] == '\t')
133       line++;
134     const char *end = internal_strchr(line, '\n');
135     if (end == 0)
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'))
140         end2--;
141       int type;
142       for (type = 0; type < SuppressionTypeCount; type++) {
143         const char *next_char = StripPrefix(line, kTypeStrings[type]);
144         if (next_char && *next_char == ':') {
145           line = ++next_char;
146           break;
147         }
148       }
149       if (type == SuppressionTypeCount) {
150         Printf("%s: failed to parse suppressions\n", SanitizerToolName);
151         Die();
152       }
153       Suppression s;
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;
158       s.hit_count = 0;
159       s.weight = 0;
160       suppressions_.push_back(s);
161       has_suppresson_type_[s.type] = true;
162     }
163     if (end[0] == 0)
164       break;
165     line = end + 1;
166   }
167 }
168
169 uptr SuppressionContext::SuppressionCount() const {
170   return suppressions_.size();
171 }
172
173 bool SuppressionContext::HasSuppressionType(SuppressionType type) const {
174   return has_suppresson_type_[type];
175 }
176
177 const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
178   CHECK_LT(i, suppressions_.size());
179   return &suppressions_[i];
180 }
181
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]);
187 }
188
189 const char *SuppressionTypeString(SuppressionType t) {
190   CHECK(t < SuppressionTypeCount);
191   return kTypeStrings[t];
192 }
193
194 }  // namespace __sanitizer