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