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