blob: 0ac2526ce524e3735d0cc4a1810eff98b6ba111d [file] [log] [blame]
Alexey Samsonov603c4be2012-06-04 13:55:19 +00001//===-- tsan_suppressions.cc ----------------------------------------------===//
Kostya Serebryany7ac41482012-05-10 13:48:04 +00002//
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
Alexey Samsonov0969bcf2012-06-18 08:44:30 +000014#include "sanitizer_common/sanitizer_common.h"
Alexey Samsonov7f9c5a22012-06-05 07:46:31 +000015#include "sanitizer_common/sanitizer_libc.h"
Sergey Matveeva52e5c62013-06-26 15:37:14 +000016#include "sanitizer_common/sanitizer_placement_new.h"
17#include "sanitizer_common/sanitizer_suppressions.h"
Kostya Serebryany7ac41482012-05-10 13:48:04 +000018#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
Dmitry Vyukova1174922013-09-03 11:43:04 +000024// 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"
Dmitry Vyukova1174922013-09-03 11:43:04 +000030// 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.
Alexey Samsonovda506a92013-09-03 11:50:48 +000033"race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n";
Dmitry Vyukova1174922013-09-03 11:43:04 +000034
Dmitry Vyukovc2b9f1c2013-01-24 13:50:10 +000035// Can be overriden in frontend.
36#ifndef TSAN_GO
37extern "C" const char *WEAK __tsan_default_suppressions() {
38 return 0;
39}
40#endif
41
Kostya Serebryany7ac41482012-05-10 13:48:04 +000042namespace __tsan {
43
Sergey Matveeva52e5c62013-06-26 15:37:14 +000044static SuppressionContext* g_ctx;
Kostya Serebryany7ac41482012-05-10 13:48:04 +000045
46static char *ReadFile(const char *filename) {
47 if (filename == 0 || filename[0] == 0)
48 return 0;
Alexey Samsonov14c8bd72012-08-22 07:25:52 +000049 InternalScopedBuffer<char> tmp(4*1024);
Dmitry Vyukov6422c322012-12-04 07:27:32 +000050 if (filename[0] == '/' || GetPwd() == 0)
Alexey Samsonov1dc4cf72012-09-05 07:23:44 +000051 internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
Kostya Serebryany7ac41482012-05-10 13:48:04 +000052 else
Alexey Samsonov1dc4cf72012-09-05 07:23:44 +000053 internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000054 uptr openrv = OpenFile(tmp.data(), false);
55 if (internal_iserror(openrv)) {
Alexey Samsonovb1fe3022012-11-02 12:17:51 +000056 Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
Alexey Samsonov14c8bd72012-08-22 07:25:52 +000057 tmp.data());
Kostya Serebryany7ac41482012-05-10 13:48:04 +000058 Die();
59 }
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000060 fd_t fd = openrv;
Kostya Serebryany7ac41482012-05-10 13:48:04 +000061 const uptr fsize = internal_filesize(fd);
62 if (fsize == (uptr)-1) {
Alexey Samsonovb1fe3022012-11-02 12:17:51 +000063 Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
Alexey Samsonov14c8bd72012-08-22 07:25:52 +000064 tmp.data());
Kostya Serebryany7ac41482012-05-10 13:48:04 +000065 Die();
66 }
67 char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
68 if (fsize != internal_read(fd, buf, fsize)) {
Alexey Samsonovb1fe3022012-11-02 12:17:51 +000069 Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
Alexey Samsonov14c8bd72012-08-22 07:25:52 +000070 tmp.data());
Kostya Serebryany7ac41482012-05-10 13:48:04 +000071 Die();
72 }
73 internal_close(fd);
74 buf[fsize] = 0;
75 return buf;
76}
77
Kostya Serebryany7ac41482012-05-10 13:48:04 +000078void InitializeSuppressions() {
Sergey Matveeva52e5c62013-06-26 15:37:14 +000079 ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
80 g_ctx = new(placeholder_) SuppressionContext;
Dmitry Vyukovc2b9f1c2013-01-24 13:50:10 +000081 const char *supp = ReadFile(flags()->suppressions);
Sergey Matveeva52e5c62013-06-26 15:37:14 +000082 g_ctx->Parse(supp);
Dmitry Vyukovc2b9f1c2013-01-24 13:50:10 +000083#ifndef TSAN_GO
84 supp = __tsan_default_suppressions();
Sergey Matveeva52e5c62013-06-26 15:37:14 +000085 g_ctx->Parse(supp);
Dmitry Vyukova1174922013-09-03 11:43:04 +000086 g_ctx->Parse(std_suppressions);
Dmitry Vyukovc2b9f1c2013-01-24 13:50:10 +000087#endif
Kostya Serebryany7ac41482012-05-10 13:48:04 +000088}
89
Dmitry Vyukov4af0f212013-10-03 13:37:17 +000090SuppressionContext *GetSuppressionContext() {
91 CHECK_NE(g_ctx, 0);
92 return g_ctx;
93}
94
Dmitry Vyukov39968332013-06-10 15:38:44 +000095SuppressionType conv(ReportType typ) {
96 if (typ == ReportTypeRace)
97 return SuppressionRace;
98 else if (typ == ReportTypeVptrRace)
99 return SuppressionRace;
100 else if (typ == ReportTypeUseAfterFree)
Alexander Potapenko45c652e2013-08-07 12:39:00 +0000101 return SuppressionRace;
Dmitry Vyukov39968332013-06-10 15:38:44 +0000102 else if (typ == ReportTypeThreadLeak)
103 return SuppressionThread;
104 else if (typ == ReportTypeMutexDestroyLocked)
105 return SuppressionMutex;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700106 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;
Dmitry Vyukov39968332013-06-10 15:38:44 +0000114 else if (typ == ReportTypeSignalUnsafe)
115 return SuppressionSignal;
116 else if (typ == ReportTypeErrnoInSignal)
117 return SuppressionNone;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700118 else if (typ == ReportTypeDeadlock)
119 return SuppressionDeadlock;
Dmitry Vyukov39968332013-06-10 15:38:44 +0000120 Printf("ThreadSanitizer: unknown report type %d\n", typ),
121 Die();
122}
123
Dmitry Vyukovf754eb52013-03-27 17:59:57 +0000124uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000125 CHECK(g_ctx);
126 if (!g_ctx->SuppressionCount() || stack == 0) return 0;
Dmitry Vyukov39968332013-06-10 15:38:44 +0000127 SuppressionType stype = conv(typ);
128 if (stype == SuppressionNone)
Dmitry Vyukov24cdfee2013-05-29 11:23:54 +0000129 return 0;
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000130 Suppression *s;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000131 for (const ReportStack *frame = stack; frame; frame = frame->next) {
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000132 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;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000139 }
140 }
Dmitry Vyukov158c6ac2012-10-05 15:51:32 +0000141 return 0;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000142}
Dmitry Vyukovf754eb52013-03-27 17:59:57 +0000143
Dmitry Vyukov39968332013-06-10 15:38:44 +0000144uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000145 CHECK(g_ctx);
146 if (!g_ctx->SuppressionCount() || loc == 0 ||
147 loc->type != ReportLocationGlobal)
Dmitry Vyukov39968332013-06-10 15:38:44 +0000148 return 0;
149 SuppressionType stype = conv(typ);
150 if (stype == SuppressionNone)
151 return 0;
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000152 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)) {
Sergey Matveevf2c84452013-06-26 16:49:34 +0000156 DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000157 s->hit_count++;
158 *sp = s;
Dmitry Vyukov39968332013-06-10 15:38:44 +0000159 return loc->addr;
Dmitry Vyukov39968332013-06-10 15:38:44 +0000160 }
161 return 0;
162}
163
Dmitry Vyukovf754eb52013-03-27 17:59:57 +0000164void PrintMatchedSuppressions() {
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000165 CHECK(g_ctx);
166 InternalMmapVector<Suppression *> matched(1);
167 g_ctx->GetMatched(&matched);
168 if (!matched.size())
Dmitry Vyukovf754eb52013-03-27 17:59:57 +0000169 return;
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000170 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);
Dmitry Vyukovf754eb52013-03-27 17:59:57 +0000178 }
179}
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000180} // namespace __tsan