sanitizer_suppressions.cc revision 4af0f21c0c98950df1136dbec8824a029ed5bb8e
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_libc.h"
19
20namespace __sanitizer {
21
22static const char *const kTypeStrings[SuppressionTypeCount] = {
23  "none", "race", "mutex", "thread", "signal", "leak", "called_from_lib"
24};
25
26bool 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++;
33  }
34  bool asterisk = false;
35  while (templ && templ[0]) {
36    if (templ[0] == '*') {
37      templ++;
38      start = false;
39      asterisk = true;
40      continue;
41    }
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;
64  }
65  return true;
66}
67
68bool SuppressionContext::Match(const char *str, SuppressionType type,
69                               Suppression **s) {
70  can_parse_ = false;
71  uptr i;
72  for (i = 0; i < suppressions_.size(); i++)
73    if (type == suppressions_[i].type &&
74        TemplateMatch(suppressions_[i].templ, str))
75      break;
76  if (i == suppressions_.size()) return false;
77  *s = &suppressions_[i];
78  return true;
79}
80
81static const char *StripPrefix(const char *str, const char *prefix) {
82  while (str && *str == *prefix) {
83    str++;
84    prefix++;
85  }
86  if (!*prefix)
87    return str;
88  return 0;
89}
90
91void SuppressionContext::Parse(const char *str) {
92  // Context must not mutate once Match has been called.
93  CHECK(can_parse_);
94  const char *line = str;
95  while (line) {
96    while (line[0] == ' ' || line[0] == '\t')
97      line++;
98    const char *end = internal_strchr(line, '\n');
99    if (end == 0)
100      end = line + internal_strlen(line);
101    if (line != end && line[0] != '#') {
102      const char *end2 = end;
103      while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
104        end2--;
105      int type;
106      for (type = 0; type < SuppressionTypeCount; type++) {
107        const char *next_char = StripPrefix(line, kTypeStrings[type]);
108        if (next_char && *next_char == ':') {
109          line = ++next_char;
110          break;
111        }
112      }
113      if (type == SuppressionTypeCount) {
114        Printf("%s: failed to parse suppressions\n", SanitizerToolName);
115        Die();
116      }
117      Suppression s;
118      s.type = static_cast<SuppressionType>(type);
119      s.templ = (char*)InternalAlloc(end2 - line + 1);
120      internal_memcpy(s.templ, line, end2 - line);
121      s.templ[end2 - line] = 0;
122      s.hit_count = 0;
123      s.weight = 0;
124      suppressions_.push_back(s);
125    }
126    if (end[0] == 0)
127      break;
128    line = end + 1;
129  }
130}
131
132uptr SuppressionContext::SuppressionCount() const {
133  return suppressions_.size();
134}
135
136const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
137  CHECK_LT(i, suppressions_.size());
138  return &suppressions_[i];
139}
140
141void SuppressionContext::GetMatched(
142    InternalMmapVector<Suppression *> *matched) {
143  for (uptr i = 0; i < suppressions_.size(); i++)
144    if (suppressions_[i].hit_count)
145      matched->push_back(&suppressions_[i]);
146}
147
148const char *SuppressionTypeString(SuppressionType t) {
149  CHECK(t < SuppressionTypeCount);
150  return kTypeStrings[t];
151}
152
153}  // namespace __sanitizer
154