blob: 22e07aadb3015a19028dfcda9263bb64124dd152 [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 Vyukovc2b9f1c2013-01-24 13:50:10 +000024// Can be overriden in frontend.
25#ifndef TSAN_GO
26extern "C" const char *WEAK __tsan_default_suppressions() {
27 return 0;
28}
29#endif
30
Kostya Serebryany7ac41482012-05-10 13:48:04 +000031namespace __tsan {
32
Sergey Matveeva52e5c62013-06-26 15:37:14 +000033static SuppressionContext* g_ctx;
Kostya Serebryany7ac41482012-05-10 13:48:04 +000034
35static char *ReadFile(const char *filename) {
36 if (filename == 0 || filename[0] == 0)
37 return 0;
Alexey Samsonov14c8bd72012-08-22 07:25:52 +000038 InternalScopedBuffer<char> tmp(4*1024);
Dmitry Vyukov6422c322012-12-04 07:27:32 +000039 if (filename[0] == '/' || GetPwd() == 0)
Alexey Samsonov1dc4cf72012-09-05 07:23:44 +000040 internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
Kostya Serebryany7ac41482012-05-10 13:48:04 +000041 else
Alexey Samsonov1dc4cf72012-09-05 07:23:44 +000042 internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000043 uptr openrv = OpenFile(tmp.data(), false);
44 if (internal_iserror(openrv)) {
Alexey Samsonovb1fe3022012-11-02 12:17:51 +000045 Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
Alexey Samsonov14c8bd72012-08-22 07:25:52 +000046 tmp.data());
Kostya Serebryany7ac41482012-05-10 13:48:04 +000047 Die();
48 }
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000049 fd_t fd = openrv;
Kostya Serebryany7ac41482012-05-10 13:48:04 +000050 const uptr fsize = internal_filesize(fd);
51 if (fsize == (uptr)-1) {
Alexey Samsonovb1fe3022012-11-02 12:17:51 +000052 Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
Alexey Samsonov14c8bd72012-08-22 07:25:52 +000053 tmp.data());
Kostya Serebryany7ac41482012-05-10 13:48:04 +000054 Die();
55 }
56 char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
57 if (fsize != internal_read(fd, buf, fsize)) {
Alexey Samsonovb1fe3022012-11-02 12:17:51 +000058 Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
Alexey Samsonov14c8bd72012-08-22 07:25:52 +000059 tmp.data());
Kostya Serebryany7ac41482012-05-10 13:48:04 +000060 Die();
61 }
62 internal_close(fd);
63 buf[fsize] = 0;
64 return buf;
65}
66
Kostya Serebryany7ac41482012-05-10 13:48:04 +000067void InitializeSuppressions() {
Sergey Matveeva52e5c62013-06-26 15:37:14 +000068 ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
69 g_ctx = new(placeholder_) SuppressionContext;
Dmitry Vyukovc2b9f1c2013-01-24 13:50:10 +000070 const char *supp = ReadFile(flags()->suppressions);
Sergey Matveeva52e5c62013-06-26 15:37:14 +000071 g_ctx->Parse(supp);
Dmitry Vyukovc2b9f1c2013-01-24 13:50:10 +000072#ifndef TSAN_GO
73 supp = __tsan_default_suppressions();
Sergey Matveeva52e5c62013-06-26 15:37:14 +000074 g_ctx->Parse(supp);
Dmitry Vyukovc2b9f1c2013-01-24 13:50:10 +000075#endif
Kostya Serebryany7ac41482012-05-10 13:48:04 +000076}
77
Dmitry Vyukov39968332013-06-10 15:38:44 +000078SuppressionType conv(ReportType typ) {
79 if (typ == ReportTypeRace)
80 return SuppressionRace;
81 else if (typ == ReportTypeVptrRace)
82 return SuppressionRace;
83 else if (typ == ReportTypeUseAfterFree)
84 return SuppressionNone;
85 else if (typ == ReportTypeThreadLeak)
86 return SuppressionThread;
87 else if (typ == ReportTypeMutexDestroyLocked)
88 return SuppressionMutex;
89 else if (typ == ReportTypeSignalUnsafe)
90 return SuppressionSignal;
91 else if (typ == ReportTypeErrnoInSignal)
92 return SuppressionNone;
93 Printf("ThreadSanitizer: unknown report type %d\n", typ),
94 Die();
95}
96
Dmitry Vyukovf754eb52013-03-27 17:59:57 +000097uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
Sergey Matveeva52e5c62013-06-26 15:37:14 +000098 CHECK(g_ctx);
99 if (!g_ctx->SuppressionCount() || stack == 0) return 0;
Dmitry Vyukov39968332013-06-10 15:38:44 +0000100 SuppressionType stype = conv(typ);
101 if (stype == SuppressionNone)
Dmitry Vyukov24cdfee2013-05-29 11:23:54 +0000102 return 0;
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000103 Suppression *s;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000104 for (const ReportStack *frame = stack; frame; frame = frame->next) {
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000105 if (g_ctx->Match(frame->func, stype, &s) ||
106 g_ctx->Match(frame->file, stype, &s) ||
107 g_ctx->Match(frame->module, stype, &s)) {
108 DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
109 s->hit_count++;
110 *sp = s;
111 return frame->pc;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000112 }
113 }
Dmitry Vyukov158c6ac2012-10-05 15:51:32 +0000114 return 0;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000115}
Dmitry Vyukovf754eb52013-03-27 17:59:57 +0000116
Dmitry Vyukov39968332013-06-10 15:38:44 +0000117uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000118 CHECK(g_ctx);
119 if (!g_ctx->SuppressionCount() || loc == 0 ||
120 loc->type != ReportLocationGlobal)
Dmitry Vyukov39968332013-06-10 15:38:44 +0000121 return 0;
122 SuppressionType stype = conv(typ);
123 if (stype == SuppressionNone)
124 return 0;
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000125 Suppression *s;
126 if (g_ctx->Match(loc->name, stype, &s) ||
127 g_ctx->Match(loc->file, stype, &s) ||
128 g_ctx->Match(loc->module, stype, &s)) {
Sergey Matveevf2c84452013-06-26 16:49:34 +0000129 DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000130 s->hit_count++;
131 *sp = s;
Dmitry Vyukov39968332013-06-10 15:38:44 +0000132 return loc->addr;
Dmitry Vyukov39968332013-06-10 15:38:44 +0000133 }
134 return 0;
135}
136
Dmitry Vyukovf754eb52013-03-27 17:59:57 +0000137void PrintMatchedSuppressions() {
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000138 CHECK(g_ctx);
139 InternalMmapVector<Suppression *> matched(1);
140 g_ctx->GetMatched(&matched);
141 if (!matched.size())
Dmitry Vyukovf754eb52013-03-27 17:59:57 +0000142 return;
Sergey Matveeva52e5c62013-06-26 15:37:14 +0000143 int hit_count = 0;
144 for (uptr i = 0; i < matched.size(); i++)
145 hit_count += matched[i]->hit_count;
146 Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count,
147 (int)internal_getpid());
148 for (uptr i = 0; i < matched.size(); i++) {
149 Printf("%d %s:%s\n", matched[i]->hit_count,
150 SuppressionTypeString(matched[i]->type), matched[i]->templ);
Dmitry Vyukovf754eb52013-03-27 17:59:57 +0000151 }
152}
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000153} // namespace __tsan