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