tsan_suppressions.cc revision 2d1fdb26e458c4ddc04155c1d421bced3ba90cd0
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// Suppressions for true/false positives in standard libraries.
25static const char *const std_suppressions =
26// Libstdc++ 4.4 has data races in std::string.
27// See http://crbug.com/181502 for an example.
28"race:^_M_rep$\n"
29"race:^_M_is_leaked$\n"
30// False positive when using std <thread>.
31// Happens because we miss atomic synchronization in libstdc++.
32// See http://llvm.org/bugs/show_bug.cgi?id=17066 for details.
33"race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n";
34
35// Can be overriden in frontend.
36#ifndef TSAN_GO
37extern "C" const char *WEAK __tsan_default_suppressions() {
38  return 0;
39}
40#endif
41
42namespace __tsan {
43
44static SuppressionContext* g_ctx;
45
46static char *ReadFile(const char *filename) {
47  if (filename == 0 || filename[0] == 0)
48    return 0;
49  InternalScopedBuffer<char> tmp(4*1024);
50  if (filename[0] == '/' || GetPwd() == 0)
51    internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
52  else
53    internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
54  uptr openrv = OpenFile(tmp.data(), false);
55  if (internal_iserror(openrv)) {
56    Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
57               tmp.data());
58    Die();
59  }
60  fd_t fd = openrv;
61  const uptr fsize = internal_filesize(fd);
62  if (fsize == (uptr)-1) {
63    Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
64               tmp.data());
65    Die();
66  }
67  char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
68  if (fsize != internal_read(fd, buf, fsize)) {
69    Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
70               tmp.data());
71    Die();
72  }
73  internal_close(fd);
74  buf[fsize] = 0;
75  return buf;
76}
77
78void InitializeSuppressions() {
79  ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
80  g_ctx = new(placeholder_) SuppressionContext;
81  const char *supp = ReadFile(flags()->suppressions);
82  g_ctx->Parse(supp);
83#ifndef TSAN_GO
84  supp = __tsan_default_suppressions();
85  g_ctx->Parse(supp);
86  g_ctx->Parse(std_suppressions);
87#endif
88}
89
90SuppressionContext *GetSuppressionContext() {
91  CHECK_NE(g_ctx, 0);
92  return g_ctx;
93}
94
95SuppressionType conv(ReportType typ) {
96  if (typ == ReportTypeRace)
97    return SuppressionRace;
98  else if (typ == ReportTypeVptrRace)
99    return SuppressionRace;
100  else if (typ == ReportTypeUseAfterFree)
101    return SuppressionRace;
102  else if (typ == ReportTypeThreadLeak)
103    return SuppressionThread;
104  else if (typ == ReportTypeMutexDestroyLocked)
105    return SuppressionMutex;
106  else if (typ == ReportTypeMutexDoubleLock)
107    return SuppressionMutex;
108  else if (typ == ReportTypeMutexBadUnlock)
109    return SuppressionMutex;
110  else if (typ == ReportTypeMutexBadReadLock)
111    return SuppressionMutex;
112  else if (typ == ReportTypeMutexBadReadUnlock)
113    return SuppressionMutex;
114  else if (typ == ReportTypeSignalUnsafe)
115    return SuppressionSignal;
116  else if (typ == ReportTypeErrnoInSignal)
117    return SuppressionNone;
118  else if (typ == ReportTypeDeadlock)
119    return SuppressionDeadlock;
120  Printf("ThreadSanitizer: unknown report type %d\n", typ),
121  Die();
122}
123
124uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
125  CHECK(g_ctx);
126  if (!g_ctx->SuppressionCount() || stack == 0) return 0;
127  SuppressionType stype = conv(typ);
128  if (stype == SuppressionNone)
129    return 0;
130  Suppression *s;
131  for (const ReportStack *frame = stack; frame; frame = frame->next) {
132    if (g_ctx->Match(frame->func, stype, &s) ||
133        g_ctx->Match(frame->file, stype, &s) ||
134        g_ctx->Match(frame->module, stype, &s)) {
135      DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
136      s->hit_count++;
137      *sp = s;
138      return frame->pc;
139    }
140  }
141  return 0;
142}
143
144uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
145  CHECK(g_ctx);
146  if (!g_ctx->SuppressionCount() || loc == 0 ||
147      loc->type != ReportLocationGlobal)
148    return 0;
149  SuppressionType stype = conv(typ);
150  if (stype == SuppressionNone)
151    return 0;
152  Suppression *s;
153  if (g_ctx->Match(loc->name, stype, &s) ||
154      g_ctx->Match(loc->file, stype, &s) ||
155      g_ctx->Match(loc->module, stype, &s)) {
156      DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
157      s->hit_count++;
158      *sp = s;
159      return loc->addr;
160  }
161  return 0;
162}
163
164void PrintMatchedSuppressions() {
165  CHECK(g_ctx);
166  InternalMmapVector<Suppression *> matched(1);
167  g_ctx->GetMatched(&matched);
168  if (!matched.size())
169    return;
170  int hit_count = 0;
171  for (uptr i = 0; i < matched.size(); i++)
172    hit_count += matched[i]->hit_count;
173  Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count,
174         (int)internal_getpid());
175  for (uptr i = 0; i < matched.size(); i++) {
176    Printf("%d %s:%s\n", matched[i]->hit_count,
177           SuppressionTypeString(matched[i]->type), matched[i]->templ);
178  }
179}
180}  // namespace __tsan
181