sanitizer_suppressions.cc revision b33cfeb6004d3a93e6d35749c14db0190c6c2b4c
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"
24};
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) {
98        Printf("%s: failed to parse suppressions\n", SanitizerToolName);
99        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;
107      s.weight = 0;
108      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
133