tsan_suppressions.cc revision a52e5c6f371bcc66e89792db1219a557664aab8d
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 "sanitizer_common/sanitizer_placement_new.h"
17#include "sanitizer_common/sanitizer_suppressions.h"
18#include "tsan_suppressions.h"
19#include "tsan_rtl.h"
20#include "tsan_flags.h"
21#include "tsan_mman.h"
22#include "tsan_platform.h"
23
24// Can be overriden in frontend.
25#ifndef TSAN_GO
26extern "C" const char *WEAK __tsan_default_suppressions() {
27  return 0;
28}
29#endif
30
31namespace __tsan {
32
33static SuppressionContext* g_ctx;
34
35static char *ReadFile(const char *filename) {
36  if (filename == 0 || filename[0] == 0)
37    return 0;
38  InternalScopedBuffer<char> tmp(4*1024);
39  if (filename[0] == '/' || GetPwd() == 0)
40    internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
41  else
42    internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
43  uptr openrv = OpenFile(tmp.data(), false);
44  if (internal_iserror(openrv)) {
45    Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
46               tmp.data());
47    Die();
48  }
49  fd_t fd = openrv;
50  const uptr fsize = internal_filesize(fd);
51  if (fsize == (uptr)-1) {
52    Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
53               tmp.data());
54    Die();
55  }
56  char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
57  if (fsize != internal_read(fd, buf, fsize)) {
58    Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
59               tmp.data());
60    Die();
61  }
62  internal_close(fd);
63  buf[fsize] = 0;
64  return buf;
65}
66
67void InitializeSuppressions() {
68  ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
69  g_ctx = new(placeholder_) SuppressionContext;
70  const char *supp = ReadFile(flags()->suppressions);
71  g_ctx->Parse(supp);
72#ifndef TSAN_GO
73  supp = __tsan_default_suppressions();
74  g_ctx->Parse(supp);
75#endif
76}
77
78SuppressionType conv(ReportType typ) {
79  if (typ == ReportTypeRace)
80    return SuppressionRace;
81  else if (typ == ReportTypeVptrRace)
82    return SuppressionRace;
83  else if (typ == ReportTypeUseAfterFree)
84    return SuppressionNone;
85  else if (typ == ReportTypeThreadLeak)
86    return SuppressionThread;
87  else if (typ == ReportTypeMutexDestroyLocked)
88    return SuppressionMutex;
89  else if (typ == ReportTypeSignalUnsafe)
90    return SuppressionSignal;
91  else if (typ == ReportTypeErrnoInSignal)
92    return SuppressionNone;
93  Printf("ThreadSanitizer: unknown report type %d\n", typ),
94  Die();
95}
96
97uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
98  CHECK(g_ctx);
99  if (!g_ctx->SuppressionCount() || stack == 0) return 0;
100  SuppressionType stype = conv(typ);
101  if (stype == SuppressionNone)
102    return 0;
103  Suppression *s;
104  for (const ReportStack *frame = stack; frame; frame = frame->next) {
105    if (g_ctx->Match(frame->func, stype, &s) ||
106        g_ctx->Match(frame->file, stype, &s) ||
107        g_ctx->Match(frame->module, stype, &s)) {
108      DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
109      s->hit_count++;
110      *sp = s;
111      return frame->pc;
112    }
113  }
114  return 0;
115}
116
117uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
118  CHECK(g_ctx);
119  if (!g_ctx->SuppressionCount() || loc == 0 ||
120      loc->type != ReportLocationGlobal)
121    return 0;
122  SuppressionType stype = conv(typ);
123  if (stype == SuppressionNone)
124    return 0;
125  Suppression *s;
126  if (g_ctx->Match(loc->name, stype, &s) ||
127      g_ctx->Match(loc->file, stype, &s) ||
128      g_ctx->Match(loc->module, stype, &s)) {
129      DPrintf("ThreadSanitizer: matched suppression '%s'\n", templ);
130      s->hit_count++;
131      *sp = s;
132      return loc->addr;
133  }
134  return 0;
135}
136
137void PrintMatchedSuppressions() {
138  CHECK(g_ctx);
139  InternalMmapVector<Suppression *> matched(1);
140  g_ctx->GetMatched(&matched);
141  if (!matched.size())
142    return;
143  int hit_count = 0;
144  for (uptr i = 0; i < matched.size(); i++)
145    hit_count += matched[i]->hit_count;
146  Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count,
147         (int)internal_getpid());
148  for (uptr i = 0; i < matched.size(); i++) {
149    Printf("%d %s:%s\n", matched[i]->hit_count,
150           SuppressionTypeString(matched[i]->type), matched[i]->templ);
151  }
152}
153}  // namespace __tsan
154