tsan_suppressions.cc revision da506a9ae831f275267ddc9ee74e5474246369b1
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
90SuppressionType conv(ReportType typ) {
91  if (typ == ReportTypeRace)
92    return SuppressionRace;
93  else if (typ == ReportTypeVptrRace)
94    return SuppressionRace;
95  else if (typ == ReportTypeUseAfterFree)
96    return SuppressionRace;
97  else if (typ == ReportTypeThreadLeak)
98    return SuppressionThread;
99  else if (typ == ReportTypeMutexDestroyLocked)
100    return SuppressionMutex;
101  else if (typ == ReportTypeSignalUnsafe)
102    return SuppressionSignal;
103  else if (typ == ReportTypeErrnoInSignal)
104    return SuppressionNone;
105  Printf("ThreadSanitizer: unknown report type %d\n", typ),
106  Die();
107}
108
109uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
110  CHECK(g_ctx);
111  if (!g_ctx->SuppressionCount() || stack == 0) return 0;
112  SuppressionType stype = conv(typ);
113  if (stype == SuppressionNone)
114    return 0;
115  Suppression *s;
116  for (const ReportStack *frame = stack; frame; frame = frame->next) {
117    if (g_ctx->Match(frame->func, stype, &s) ||
118        g_ctx->Match(frame->file, stype, &s) ||
119        g_ctx->Match(frame->module, stype, &s)) {
120      DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
121      s->hit_count++;
122      *sp = s;
123      return frame->pc;
124    }
125  }
126  return 0;
127}
128
129uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
130  CHECK(g_ctx);
131  if (!g_ctx->SuppressionCount() || loc == 0 ||
132      loc->type != ReportLocationGlobal)
133    return 0;
134  SuppressionType stype = conv(typ);
135  if (stype == SuppressionNone)
136    return 0;
137  Suppression *s;
138  if (g_ctx->Match(loc->name, stype, &s) ||
139      g_ctx->Match(loc->file, stype, &s) ||
140      g_ctx->Match(loc->module, stype, &s)) {
141      DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
142      s->hit_count++;
143      *sp = s;
144      return loc->addr;
145  }
146  return 0;
147}
148
149void PrintMatchedSuppressions() {
150  CHECK(g_ctx);
151  InternalMmapVector<Suppression *> matched(1);
152  g_ctx->GetMatched(&matched);
153  if (!matched.size())
154    return;
155  int hit_count = 0;
156  for (uptr i = 0; i < matched.size(); i++)
157    hit_count += matched[i]->hit_count;
158  Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count,
159         (int)internal_getpid());
160  for (uptr i = 0; i < matched.size(); i++) {
161    Printf("%d %s:%s\n", matched[i]->hit_count,
162           SuppressionTypeString(matched[i]->type), matched[i]->templ);
163  }
164}
165}  // namespace __tsan
166