blob: 7f76693e57cb4d15c4c82444bb7320cf0e4614a0 [file] [log] [blame]
Sergey Matveeva52e5c62013-06-26 15:37:14 +00001//===-- 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"
Stephen Hines6d186232014-11-26 17:56:19 -080018#include "sanitizer_flags.h"
Sergey Matveeva52e5c62013-06-26 15:37:14 +000019#include "sanitizer_libc.h"
Stephen Hines6d186232014-11-26 17:56:19 -080020#include "sanitizer_placement_new.h"
Sergey Matveeva52e5c62013-06-26 15:37:14 +000021
22namespace __sanitizer {
23
24static const char *const kTypeStrings[SuppressionTypeCount] = {
Stephen Hines6d186232014-11-26 17:56:19 -080025 "none", "race", "mutex", "thread", "signal",
26 "leak", "called_from_lib", "deadlock", "vptr_check"};
Sergey Matveeva52e5c62013-06-26 15:37:14 +000027
28bool TemplateMatch(char *templ, const char *str) {
29 if (str == 0 || str[0] == 0)
30 return false;
Dmitry Vyukov55e6f3f2013-07-16 16:44:15 +000031 bool start = false;
32 if (templ && templ[0] == '^') {
33 start = true;
34 templ++;
35 }
36 bool asterisk = false;
Sergey Matveeva52e5c62013-06-26 15:37:14 +000037 while (templ && templ[0]) {
38 if (templ[0] == '*') {
39 templ++;
Dmitry Vyukov55e6f3f2013-07-16 16:44:15 +000040 start = false;
41 asterisk = true;
Sergey Matveeva52e5c62013-06-26 15:37:14 +000042 continue;
43 }
Dmitry Vyukov55e6f3f2013-07-16 16:44:15 +000044 if (templ[0] == '$')
45 return str[0] == 0 || asterisk;
Sergey Matveeva52e5c62013-06-26 15:37:14 +000046 if (str[0] == 0)
47 return false;
Dmitry Vyukov55e6f3f2013-07-16 16:44:15 +000048 char *tpos = (char*)internal_strchr(templ, '*');
49 char *tpos1 = (char*)internal_strchr(templ, '$');
50 if (tpos == 0 || (tpos1 && tpos1 < tpos))
51 tpos = tpos1;
Sergey Matveeva52e5c62013-06-26 15:37:14 +000052 if (tpos != 0)
53 tpos[0] = 0;
Dmitry Vyukov55e6f3f2013-07-16 16:44:15 +000054 const char *str0 = str;
55 const char *spos = internal_strstr(str, templ);
Sergey Matveeva52e5c62013-06-26 15:37:14 +000056 str = spos + internal_strlen(templ);
57 templ = tpos;
58 if (tpos)
Dmitry Vyukov55e6f3f2013-07-16 16:44:15 +000059 tpos[0] = tpos == tpos1 ? '$' : '*';
Sergey Matveeva52e5c62013-06-26 15:37:14 +000060 if (spos == 0)
61 return false;
Dmitry Vyukov55e6f3f2013-07-16 16:44:15 +000062 if (start && spos != str0)
63 return false;
64 start = false;
65 asterisk = false;
Sergey Matveeva52e5c62013-06-26 15:37:14 +000066 }
67 return true;
68}
69
Stephen Hines6d186232014-11-26 17:56:19 -080070ALIGNED(64) static char placeholder[sizeof(SuppressionContext)];
71static SuppressionContext *suppression_ctx = 0;
72
73SuppressionContext *SuppressionContext::Get() {
74 CHECK(suppression_ctx);
75 return suppression_ctx;
76}
77
78void SuppressionContext::InitIfNecessary() {
79 if (suppression_ctx)
80 return;
81 suppression_ctx = new(placeholder) SuppressionContext;
82 if (common_flags()->suppressions[0] == '\0')
83 return;
84 char *suppressions_from_file;
85 uptr buffer_size;
86 uptr contents_size =
87 ReadFileToBuffer(common_flags()->suppressions, &suppressions_from_file,
88 &buffer_size, 1 << 26 /* max_len */);
89 if (contents_size == 0) {
90 Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
91 common_flags()->suppressions);
92 Die();
93 }
94 suppression_ctx->Parse(suppressions_from_file);
95}
96
Sergey Matveeva52e5c62013-06-26 15:37:14 +000097bool SuppressionContext::Match(const char *str, SuppressionType type,
98 Suppression **s) {
99 can_parse_ = false;
100 uptr i;
101 for (i = 0; i < suppressions_.size(); i++)
102 if (type == suppressions_[i].type &&
103 TemplateMatch(suppressions_[i].templ, str))
104 break;
105 if (i == suppressions_.size()) return false;
106 *s = &suppressions_[i];
107 return true;
108}
109
110static const char *StripPrefix(const char *str, const char *prefix) {
111 while (str && *str == *prefix) {
112 str++;
113 prefix++;
114 }
115 if (!*prefix)
116 return str;
117 return 0;
118}
119
120void SuppressionContext::Parse(const char *str) {
121 // Context must not mutate once Match has been called.
122 CHECK(can_parse_);
123 const char *line = str;
124 while (line) {
125 while (line[0] == ' ' || line[0] == '\t')
126 line++;
127 const char *end = internal_strchr(line, '\n');
128 if (end == 0)
129 end = line + internal_strlen(line);
130 if (line != end && line[0] != '#') {
131 const char *end2 = end;
132 while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
133 end2--;
134 int type;
135 for (type = 0; type < SuppressionTypeCount; type++) {
136 const char *next_char = StripPrefix(line, kTypeStrings[type]);
137 if (next_char && *next_char == ':') {
138 line = ++next_char;
139 break;
140 }
141 }
142 if (type == SuppressionTypeCount) {
Sergey Matveevb33cfeb2013-06-28 14:38:31 +0000143 Printf("%s: failed to parse suppressions\n", SanitizerToolName);
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000144 Die();
145 }
146 Suppression s;
147 s.type = static_cast<SuppressionType>(type);
148 s.templ = (char*)InternalAlloc(end2 - line + 1);
149 internal_memcpy(s.templ, line, end2 - line);
150 s.templ[end2 - line] = 0;
151 s.hit_count = 0;
Sergey Matveevb33cfeb2013-06-28 14:38:31 +0000152 s.weight = 0;
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000153 suppressions_.push_back(s);
154 }
155 if (end[0] == 0)
156 break;
157 line = end + 1;
158 }
159}
160
Dmitry Vyukov4af0f212013-10-03 13:37:17 +0000161uptr SuppressionContext::SuppressionCount() const {
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000162 return suppressions_.size();
163}
164
Dmitry Vyukov4af0f212013-10-03 13:37:17 +0000165const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
166 CHECK_LT(i, suppressions_.size());
167 return &suppressions_[i];
168}
169
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000170void SuppressionContext::GetMatched(
171 InternalMmapVector<Suppression *> *matched) {
172 for (uptr i = 0; i < suppressions_.size(); i++)
173 if (suppressions_[i].hit_count)
174 matched->push_back(&suppressions_[i]);
175}
176
177const char *SuppressionTypeString(SuppressionType t) {
178 CHECK(t < SuppressionTypeCount);
179 return kTypeStrings[t];
180}
181
182} // namespace __sanitizer