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 // Can be overriden in frontend.
25 #ifndef TSAN_GO
__tsan_default_suppressions()26 extern "C" const char *WEAK __tsan_default_suppressions() {
27 return 0;
28 }
29 #endif
30
31 namespace __tsan {
32
33 static SuppressionContext* g_ctx;
34
ReadFile(const char * filename)35 static char *ReadFile(const char *filename) {
36 if (filename == 0 || filename[0] == 0)
37 return 0;
38 InternalScopedBuffer<char> tmp(4*1024);
39 if (filename[0] == '/' || GetPwd() == 0)
40 internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
41 else
42 internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
43 uptr openrv = OpenFile(tmp.data(), false);
44 if (internal_iserror(openrv)) {
45 Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
46 tmp.data());
47 Die();
48 }
49 fd_t fd = openrv;
50 const uptr fsize = internal_filesize(fd);
51 if (fsize == (uptr)-1) {
52 Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
53 tmp.data());
54 Die();
55 }
56 char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
57 if (fsize != internal_read(fd, buf, fsize)) {
58 Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
59 tmp.data());
60 Die();
61 }
62 internal_close(fd);
63 buf[fsize] = 0;
64 return buf;
65 }
66
InitializeSuppressions()67 void InitializeSuppressions() {
68 ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
69 g_ctx = new(placeholder_) SuppressionContext;
70 const char *supp = ReadFile(flags()->suppressions);
71 g_ctx->Parse(supp);
72 #ifndef TSAN_GO
73 supp = __tsan_default_suppressions();
74 g_ctx->Parse(supp);
75 #endif
76 }
77
conv(ReportType typ)78 SuppressionType 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 SuppressionRace;
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
IsSuppressed(ReportType typ,const ReportStack * stack,Suppression ** sp)97 uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
98 CHECK(g_ctx);
99 if (!g_ctx->SuppressionCount() || stack == 0) return 0;
100 SuppressionType stype = conv(typ);
101 if (stype == SuppressionNone)
102 return 0;
103 Suppression *s;
104 for (const ReportStack *frame = stack; frame; frame = frame->next) {
105 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;
112 }
113 }
114 return 0;
115 }
116
IsSuppressed(ReportType typ,const ReportLocation * loc,Suppression ** sp)117 uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
118 CHECK(g_ctx);
119 if (!g_ctx->SuppressionCount() || loc == 0 ||
120 loc->type != ReportLocationGlobal)
121 return 0;
122 SuppressionType stype = conv(typ);
123 if (stype == SuppressionNone)
124 return 0;
125 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)) {
129 DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
130 s->hit_count++;
131 *sp = s;
132 return loc->addr;
133 }
134 return 0;
135 }
136
PrintMatchedSuppressions()137 void PrintMatchedSuppressions() {
138 CHECK(g_ctx);
139 InternalMmapVector<Suppression *> matched(1);
140 g_ctx->GetMatched(&matched);
141 if (!matched.size())
142 return;
143 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);
151 }
152 }
153 } // namespace __tsan
154