tsan_suppressions.cc revision ee7cc4454421a176d23442382afd9a01d36e7ad4
1793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//===-- tsan_suppressions.cc ----------------------------------------------===//
2793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
3793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//                     The LLVM Compiler Infrastructure
4793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
5793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// This file is distributed under the University of Illinois Open Source
6793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// License. See LICENSE.TXT for details.
7793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
8793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//===----------------------------------------------------------------------===//
9793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
10793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// This file is a part of ThreadSanitizer (TSan), a race detector.
11793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
12793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//===----------------------------------------------------------------------===//
13793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
14793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "sanitizer_common/sanitizer_common.h"
15793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "sanitizer_common/sanitizer_libc.h"
16793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "tsan_suppressions.h"
17793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "tsan_rtl.h"
18793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "tsan_flags.h"
19793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "tsan_mman.h"
20793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "tsan_platform.h"
21793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
22793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Can be overriden in frontend.
23793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifndef TSAN_GO
24793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerextern "C" const char *WEAK __tsan_default_suppressions() {
25793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  return 0;
26793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
27793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif
28793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
29793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslernamespace __tsan {
30793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
31793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic Suppression *g_suppressions;
32793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
33793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic char *ReadFile(const char *filename) {
34793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  if (filename == 0 || filename[0] == 0)
35793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return 0;
36793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  InternalScopedBuffer<char> tmp(4*1024);
37793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  if (filename[0] == '/' || GetPwd() == 0)
38793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
39793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  else
40793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
41793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  fd_t fd = OpenFile(tmp.data(), false);
42793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  if (fd == kInvalidFd) {
43793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
44793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler               tmp.data());
45793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Die();
46793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  }
47793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  const uptr fsize = internal_filesize(fd);
48793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  if (fsize == (uptr)-1) {
49793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
50793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler               tmp.data());
51793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Die();
52793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  }
53793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
54793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  if (fsize != internal_read(fd, buf, fsize)) {
55793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
56793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler               tmp.data());
57793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Die();
58793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  }
59793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  internal_close(fd);
60793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  buf[fsize] = 0;
61793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  return buf;
62793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
63793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
64793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerbool SuppressionMatch(char *templ, const char *str) {
65793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  if (str == 0 || str[0] == 0)
66793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return false;
67793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  char *tpos;
68793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  const char *spos;
69793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  while (templ && templ[0]) {
70793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if (templ[0] == '*') {
71793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      templ++;
72793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      continue;
73793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
74793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if (str[0] == 0)
75793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      return false;
76793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    tpos = (char*)internal_strchr(templ, '*');
77793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if (tpos != 0)
78793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      tpos[0] = 0;
79793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    spos = internal_strstr(str, templ);
80793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    str = spos + internal_strlen(templ);
81793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    templ = tpos;
82793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if (tpos)
83793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      tpos[0] = '*';
84793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if (spos == 0)
85793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      return false;
86793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  }
87793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  return true;
88793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
89793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
90793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerSuppression *SuppressionParse(Suppression *head, const char* supp) {
91793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  const char *line = supp;
92793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  while (line) {
93793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    while (line[0] == ' ' || line[0] == '\t')
94793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      line++;
95793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    const char *end = internal_strchr(line, '\n');
96793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if (end == 0)
97793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      end = line + internal_strlen(line);
98793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if (line != end && line[0] != '#') {
99793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      const char *end2 = end;
100793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
101793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        end2--;
102793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      SuppressionType stype;
103793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) {
104793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        stype = SuppressionRace;
105793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        line += sizeof("race:") - 1;
106793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      } else if (0 == internal_strncmp(line, "thread:",
107793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler          sizeof("thread:") - 1)) {
108793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        stype = SuppressionThread;
109793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        line += sizeof("thread:") - 1;
110793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      } else if (0 == internal_strncmp(line, "mutex:",
111793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler          sizeof("mutex:") - 1)) {
112793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        stype = SuppressionMutex;
113793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        line += sizeof("mutex:") - 1;
114793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      } else if (0 == internal_strncmp(line, "signal:",
115793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler          sizeof("signal:") - 1)) {
116793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        stype = SuppressionSignal;
117793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        line += sizeof("signal:") - 1;
118793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      } else {
119793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        Printf("ThreadSanitizer: failed to parse suppressions file\n");
120793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        Die();
121793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      }
122793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
123793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler          sizeof(Suppression));
124793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      s->next = head;
125793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      head = s;
126793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      s->type = stype;
127793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
128793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      internal_memcpy(s->templ, line, end2 - line);
129793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      s->templ[end2 - line] = 0;
130793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
131793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if (end[0] == 0)
132793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      break;
133793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    line = end + 1;
134793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  }
135793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  return head;
136793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
137793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
138793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslervoid InitializeSuppressions() {
139793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  const char *supp = ReadFile(flags()->suppressions);
140793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  g_suppressions = SuppressionParse(0, supp);
141793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifndef TSAN_GO
142793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  supp = __tsan_default_suppressions();
143793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  g_suppressions = SuppressionParse(0, supp);
144793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif
145793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
146793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
147793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presleruptr IsSuppressed(ReportType typ, const ReportStack *stack) {
148793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  if (g_suppressions == 0 || stack == 0)
149793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return 0;
150793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  SuppressionType stype;
151793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  if (typ == ReportTypeRace)
152793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    stype = SuppressionRace;
153793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  else if (typ == ReportTypeThreadLeak)
154793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    stype = SuppressionThread;
155793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  else if (typ == ReportTypeMutexDestroyLocked)
156793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    stype = SuppressionMutex;
157793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  else if (typ == ReportTypeSignalUnsafe)
158793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    stype = SuppressionSignal;
159793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  else
160793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return 0;
161793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  for (const ReportStack *frame = stack; frame; frame = frame->next) {
162793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
163793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      if (stype == supp->type &&
164793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler          (SuppressionMatch(supp->templ, frame->func) ||
165793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler           SuppressionMatch(supp->templ, frame->file) ||
166793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler           SuppressionMatch(supp->templ, frame->module))) {
167793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
168793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        return frame->pc;
169793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      }
170793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
171793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  }
172793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler  return 0;
173793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
174793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}  // namespace __tsan
175793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler