1a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev//===-- sanitizer_suppressions.cc -----------------------------------------===//
2a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev//
3a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev//                     The LLVM Compiler Infrastructure
4a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev//
5a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev// This file is distributed under the University of Illinois Open Source
6a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev// License. See LICENSE.TXT for details.
7a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev//
8a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev//===----------------------------------------------------------------------===//
9a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev//
10a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev// Suppression parsing/matching code shared between TSan and LSan.
11a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev//
12a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev//===----------------------------------------------------------------------===//
13a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev
14a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev#include "sanitizer_suppressions.h"
15a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev
16a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev#include "sanitizer_allocator_internal.h"
17a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev#include "sanitizer_common.h"
18a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev#include "sanitizer_libc.h"
19a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev
20a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveevnamespace __sanitizer {
21a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev
22a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveevstatic const char *const kTypeStrings[SuppressionTypeCount] = {
23b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev  "none", "race", "mutex", "thread", "signal", "leak"
24a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev};
25a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev
26a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveevbool TemplateMatch(char *templ, const char *str) {
27a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  if (str == 0 || str[0] == 0)
28a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    return false;
2955e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov  bool start = false;
3055e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov  if (templ && templ[0] == '^') {
3155e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov    start = true;
3255e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov    templ++;
3355e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov  }
3455e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov  bool asterisk = false;
35a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  while (templ && templ[0]) {
36a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    if (templ[0] == '*') {
37a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      templ++;
3855e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov      start = false;
3955e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov      asterisk = true;
40a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      continue;
41a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    }
4255e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov    if (templ[0] == '$')
4355e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov      return str[0] == 0 || asterisk;
44a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    if (str[0] == 0)
45a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      return false;
4655e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov    char *tpos = (char*)internal_strchr(templ, '*');
4755e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov    char *tpos1 = (char*)internal_strchr(templ, '$');
4855e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov    if (tpos == 0 || (tpos1 && tpos1 < tpos))
4955e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov      tpos = tpos1;
50a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    if (tpos != 0)
51a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      tpos[0] = 0;
5255e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov    const char *str0 = str;
5355e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov    const char *spos = internal_strstr(str, templ);
54a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    str = spos + internal_strlen(templ);
55a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    templ = tpos;
56a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    if (tpos)
5755e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov      tpos[0] = tpos == tpos1 ? '$' : '*';
58a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    if (spos == 0)
59a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      return false;
6055e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov    if (start && spos != str0)
6155e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov      return false;
6255e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov    start = false;
6355e6f3f4e6b799e0affd13f28137661f8707133fDmitry Vyukov    asterisk = false;
64a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  }
65a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  return true;
66a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev}
67a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev
68a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveevbool SuppressionContext::Match(const char *str, SuppressionType type,
69a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev                               Suppression **s) {
70a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  can_parse_ = false;
71a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  uptr i;
72a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  for (i = 0; i < suppressions_.size(); i++)
73a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    if (type == suppressions_[i].type &&
74a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev        TemplateMatch(suppressions_[i].templ, str))
75a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      break;
76a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  if (i == suppressions_.size()) return false;
77a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  *s = &suppressions_[i];
78a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  return true;
79a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev}
80a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev
81a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveevstatic const char *StripPrefix(const char *str, const char *prefix) {
82a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  while (str && *str == *prefix) {
83a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    str++;
84a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    prefix++;
85a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  }
86a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  if (!*prefix)
87a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    return str;
88a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  return 0;
89a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev}
90a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev
91a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveevvoid SuppressionContext::Parse(const char *str) {
92a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  // Context must not mutate once Match has been called.
93a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  CHECK(can_parse_);
94a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  const char *line = str;
95a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  while (line) {
96a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    while (line[0] == ' ' || line[0] == '\t')
97a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      line++;
98a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    const char *end = internal_strchr(line, '\n');
99a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    if (end == 0)
100a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      end = line + internal_strlen(line);
101a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    if (line != end && line[0] != '#') {
102a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      const char *end2 = end;
103a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
104a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev        end2--;
105a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      int type;
106a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      for (type = 0; type < SuppressionTypeCount; type++) {
107a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev        const char *next_char = StripPrefix(line, kTypeStrings[type]);
108a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev        if (next_char && *next_char == ':') {
109a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev          line = ++next_char;
110a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev          break;
111a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev        }
112a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      }
113a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      if (type == SuppressionTypeCount) {
114b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev        Printf("%s: failed to parse suppressions\n", SanitizerToolName);
115a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev        Die();
116a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      }
117a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      Suppression s;
118a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      s.type = static_cast<SuppressionType>(type);
119a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      s.templ = (char*)InternalAlloc(end2 - line + 1);
120a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      internal_memcpy(s.templ, line, end2 - line);
121a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      s.templ[end2 - line] = 0;
122a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      s.hit_count = 0;
123b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev      s.weight = 0;
124a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      suppressions_.push_back(s);
125a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    }
126a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    if (end[0] == 0)
127a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      break;
128a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    line = end + 1;
129a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  }
130a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev}
131a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev
132a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveevuptr SuppressionContext::SuppressionCount() {
133a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  return suppressions_.size();
134a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev}
135a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev
136a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveevvoid SuppressionContext::GetMatched(
137a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    InternalMmapVector<Suppression *> *matched) {
138a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  for (uptr i = 0; i < suppressions_.size(); i++)
139a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev    if (suppressions_[i].hit_count)
140a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev      matched->push_back(&suppressions_[i]);
141a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev}
142a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev
143a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveevconst char *SuppressionTypeString(SuppressionType t) {
144a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  CHECK(t < SuppressionTypeCount);
145a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev  return kTypeStrings[t];
146a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev}
147a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev
148a52e5c6f371bcc66e89792db1219a557664aab8dSergey Matveev}  // namespace __sanitizer
149