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