blob: f88020fa639b31a587dd44f78446889044b9ecd7 [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"
18#include "sanitizer_libc.h"
19
20namespace __sanitizer {
21
22static const char *const kTypeStrings[SuppressionTypeCount] = {
Sergey Matveevb33cfeb2013-06-28 14:38:31 +000023 "none", "race", "mutex", "thread", "signal", "leak"
Sergey Matveeva52e5c62013-06-26 15:37:14 +000024};
25
26bool TemplateMatch(char *templ, const char *str) {
27 if (str == 0 || str[0] == 0)
28 return false;
29 char *tpos;
30 const char *spos;
31 while (templ && templ[0]) {
32 if (templ[0] == '*') {
33 templ++;
34 continue;
35 }
36 if (str[0] == 0)
37 return false;
38 tpos = (char*)internal_strchr(templ, '*');
39 if (tpos != 0)
40 tpos[0] = 0;
41 spos = internal_strstr(str, templ);
42 str = spos + internal_strlen(templ);
43 templ = tpos;
44 if (tpos)
45 tpos[0] = '*';
46 if (spos == 0)
47 return false;
48 }
49 return true;
50}
51
52bool SuppressionContext::Match(const char *str, SuppressionType type,
53 Suppression **s) {
54 can_parse_ = false;
55 uptr i;
56 for (i = 0; i < suppressions_.size(); i++)
57 if (type == suppressions_[i].type &&
58 TemplateMatch(suppressions_[i].templ, str))
59 break;
60 if (i == suppressions_.size()) return false;
61 *s = &suppressions_[i];
62 return true;
63}
64
65static const char *StripPrefix(const char *str, const char *prefix) {
66 while (str && *str == *prefix) {
67 str++;
68 prefix++;
69 }
70 if (!*prefix)
71 return str;
72 return 0;
73}
74
75void SuppressionContext::Parse(const char *str) {
76 // Context must not mutate once Match has been called.
77 CHECK(can_parse_);
78 const char *line = str;
79 while (line) {
80 while (line[0] == ' ' || line[0] == '\t')
81 line++;
82 const char *end = internal_strchr(line, '\n');
83 if (end == 0)
84 end = line + internal_strlen(line);
85 if (line != end && line[0] != '#') {
86 const char *end2 = end;
87 while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
88 end2--;
89 int type;
90 for (type = 0; type < SuppressionTypeCount; type++) {
91 const char *next_char = StripPrefix(line, kTypeStrings[type]);
92 if (next_char && *next_char == ':') {
93 line = ++next_char;
94 break;
95 }
96 }
97 if (type == SuppressionTypeCount) {
Sergey Matveevb33cfeb2013-06-28 14:38:31 +000098 Printf("%s: failed to parse suppressions\n", SanitizerToolName);
Sergey Matveeva52e5c62013-06-26 15:37:14 +000099 Die();
100 }
101 Suppression s;
102 s.type = static_cast<SuppressionType>(type);
103 s.templ = (char*)InternalAlloc(end2 - line + 1);
104 internal_memcpy(s.templ, line, end2 - line);
105 s.templ[end2 - line] = 0;
106 s.hit_count = 0;
Sergey Matveevb33cfeb2013-06-28 14:38:31 +0000107 s.weight = 0;
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000108 suppressions_.push_back(s);
109 }
110 if (end[0] == 0)
111 break;
112 line = end + 1;
113 }
114}
115
116uptr SuppressionContext::SuppressionCount() {
117 return suppressions_.size();
118}
119
120void SuppressionContext::GetMatched(
121 InternalMmapVector<Suppression *> *matched) {
122 for (uptr i = 0; i < suppressions_.size(); i++)
123 if (suppressions_[i].hit_count)
124 matched->push_back(&suppressions_[i]);
125}
126
127const char *SuppressionTypeString(SuppressionType t) {
128 CHECK(t < SuppressionTypeCount);
129 return kTypeStrings[t];
130}
131
132} // namespace __sanitizer