tsan_suppressions.cc revision 67a64dd8259fdbd867633b27f54d584f435f1ce6
1//===-- tsan_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// This file is a part of ThreadSanitizer (TSan), a race detector.
11//
12//===----------------------------------------------------------------------===//
13
14#include "sanitizer_common/sanitizer_libc.h"
15#include "tsan_suppressions.h"
16#include "tsan_rtl.h"
17#include "tsan_flags.h"
18#include "tsan_mman.h"
19#include "tsan_platform.h"
20
21namespace __tsan {
22
23static Suppression *g_suppressions;
24
25static char *ReadFile(const char *filename) {
26  if (filename == 0 || filename[0] == 0)
27    return 0;
28  InternalScopedBuf<char> tmp(4*1024);
29  if (filename[0] == '/')
30    SNPrintf(tmp, tmp.Size(), "%s", filename);
31  else
32    SNPrintf(tmp, tmp.Size(), "%s/%s", internal_getpwd(), filename);
33  fd_t fd = internal_open(tmp, false);
34  if (fd == kInvalidFd) {
35    TsanPrintf("ThreadSanitizer: failed to open suppressions file '%s'\n",
36        tmp.Ptr());
37    Die();
38  }
39  const uptr fsize = internal_filesize(fd);
40  if (fsize == (uptr)-1) {
41    TsanPrintf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
42        tmp.Ptr());
43    Die();
44  }
45  char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
46  if (fsize != internal_read(fd, buf, fsize)) {
47    TsanPrintf("ThreadSanitizer: failed to read suppressions file '%s'\n",
48        tmp.Ptr());
49    Die();
50  }
51  internal_close(fd);
52  buf[fsize] = 0;
53  return buf;
54}
55
56bool SuppressionMatch(char *templ, const char *str) {
57  if (str == 0 || str[0] == 0)
58    return false;
59  char *tpos;
60  const char *spos;
61  while (templ && templ[0]) {
62    if (templ[0] == '*') {
63      templ++;
64      continue;
65    }
66    if (str[0] == 0)
67      return false;
68    tpos = (char*)internal_strchr(templ, '*');
69    if (tpos != 0)
70      tpos[0] = 0;
71    spos = internal_strstr(str, templ);
72    str = spos + internal_strlen(templ);
73    templ = tpos;
74    if (tpos)
75      tpos[0] = '*';
76    if (spos == 0)
77      return false;
78  }
79  return true;
80}
81
82Suppression *SuppressionParse(const char* supp) {
83  Suppression *head = 0;
84  const char *line = supp;
85  while (line) {
86    while (line[0] == ' ' || line[0] == '\t')
87      line++;
88    const char *end = internal_strchr(line, '\n');
89    if (end == 0)
90      end = line + internal_strlen(line);
91    if (line != end && line[0] != '#') {
92      const char *end2 = end;
93      while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
94        end2--;
95      SuppressionType stype;
96      if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) {
97        stype = SuppressionRace;
98        line += sizeof("race:") - 1;
99      } else if (0 == internal_strncmp(line, "thread:",
100          sizeof("thread:") - 1)) {
101        stype = SuppressionThread;
102        line += sizeof("thread:") - 1;
103      } else if (0 == internal_strncmp(line, "mutex:",
104          sizeof("mutex:") - 1)) {
105        stype = SuppressionMutex;
106        line += sizeof("mutex:") - 1;
107      } else if (0 == internal_strncmp(line, "signal:",
108          sizeof("signal:") - 1)) {
109        stype = SuppressionSignal;
110        line += sizeof("signal:") - 1;
111      } else {
112        TsanPrintf("ThreadSanitizer: failed to parse suppressions file\n");
113        Die();
114      }
115      Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
116          sizeof(Suppression));
117      s->next = head;
118      head = s;
119      s->type = stype;
120      s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
121      internal_memcpy(s->templ, line, end2 - line);
122      s->templ[end2 - line] = 0;
123    }
124    if (end[0] == 0)
125      break;
126    line = end + 1;
127  }
128  return head;
129}
130
131void InitializeSuppressions() {
132  char *supp = ReadFile(flags()->suppressions);
133  g_suppressions = SuppressionParse(supp);
134}
135
136bool IsSuppressed(ReportType typ, const ReportStack *stack) {
137  if (g_suppressions == 0 || stack == 0)
138    return false;
139  SuppressionType stype;
140  if (typ == ReportTypeRace)
141    stype = SuppressionRace;
142  else if (typ == ReportTypeThreadLeak)
143    stype = SuppressionThread;
144  else if (typ == ReportTypeMutexDestroyLocked)
145    stype = SuppressionMutex;
146  else if (typ == ReportTypeSignalUnsafe)
147    stype = SuppressionSignal;
148  else
149    return false;
150  for (const ReportStack *frame = stack; frame; frame = frame->next) {
151    for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
152      if (stype == supp->type &&
153          (SuppressionMatch(supp->templ, frame->func) ||
154          SuppressionMatch(supp->templ, frame->file))) {
155        DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
156        return true;
157      }
158    }
159  }
160  return false;
161}
162}  // namespace __tsan
163