1*7c3d14c8STreehugger Robot //===-- tsan_suppressions.cc ----------------------------------------------===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot // The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // This file is a part of ThreadSanitizer (TSan), a race detector.
11*7c3d14c8STreehugger Robot //
12*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
13*7c3d14c8STreehugger Robot
14*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_common.h"
15*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_libc.h"
16*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_placement_new.h"
17*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_suppressions.h"
18*7c3d14c8STreehugger Robot #include "tsan_suppressions.h"
19*7c3d14c8STreehugger Robot #include "tsan_rtl.h"
20*7c3d14c8STreehugger Robot #include "tsan_flags.h"
21*7c3d14c8STreehugger Robot #include "tsan_mman.h"
22*7c3d14c8STreehugger Robot #include "tsan_platform.h"
23*7c3d14c8STreehugger Robot
24*7c3d14c8STreehugger Robot #ifndef SANITIZER_GO
25*7c3d14c8STreehugger Robot // Suppressions for true/false positives in standard libraries.
26*7c3d14c8STreehugger Robot static const char *const std_suppressions =
27*7c3d14c8STreehugger Robot // Libstdc++ 4.4 has data races in std::string.
28*7c3d14c8STreehugger Robot // See http://crbug.com/181502 for an example.
29*7c3d14c8STreehugger Robot "race:^_M_rep$\n"
30*7c3d14c8STreehugger Robot "race:^_M_is_leaked$\n"
31*7c3d14c8STreehugger Robot // False positive when using std <thread>.
32*7c3d14c8STreehugger Robot // Happens because we miss atomic synchronization in libstdc++.
33*7c3d14c8STreehugger Robot // See http://llvm.org/bugs/show_bug.cgi?id=17066 for details.
34*7c3d14c8STreehugger Robot "race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n";
35*7c3d14c8STreehugger Robot
36*7c3d14c8STreehugger Robot // Can be overriden in frontend.
37*7c3d14c8STreehugger Robot SANITIZER_WEAK_DEFAULT_IMPL
__tsan_default_suppressions()38*7c3d14c8STreehugger Robot const char *__tsan_default_suppressions() {
39*7c3d14c8STreehugger Robot return 0;
40*7c3d14c8STreehugger Robot }
41*7c3d14c8STreehugger Robot #endif
42*7c3d14c8STreehugger Robot
43*7c3d14c8STreehugger Robot namespace __tsan {
44*7c3d14c8STreehugger Robot
45*7c3d14c8STreehugger Robot ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
46*7c3d14c8STreehugger Robot static SuppressionContext *suppression_ctx = nullptr;
47*7c3d14c8STreehugger Robot static const char *kSuppressionTypes[] = {
48*7c3d14c8STreehugger Robot kSuppressionRace, kSuppressionRaceTop, kSuppressionMutex,
49*7c3d14c8STreehugger Robot kSuppressionThread, kSuppressionSignal, kSuppressionLib,
50*7c3d14c8STreehugger Robot kSuppressionDeadlock};
51*7c3d14c8STreehugger Robot
InitializeSuppressions()52*7c3d14c8STreehugger Robot void InitializeSuppressions() {
53*7c3d14c8STreehugger Robot CHECK_EQ(nullptr, suppression_ctx);
54*7c3d14c8STreehugger Robot suppression_ctx = new (suppression_placeholder) // NOLINT
55*7c3d14c8STreehugger Robot SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
56*7c3d14c8STreehugger Robot suppression_ctx->ParseFromFile(flags()->suppressions);
57*7c3d14c8STreehugger Robot #ifndef SANITIZER_GO
58*7c3d14c8STreehugger Robot suppression_ctx->Parse(__tsan_default_suppressions());
59*7c3d14c8STreehugger Robot suppression_ctx->Parse(std_suppressions);
60*7c3d14c8STreehugger Robot #endif
61*7c3d14c8STreehugger Robot }
62*7c3d14c8STreehugger Robot
Suppressions()63*7c3d14c8STreehugger Robot SuppressionContext *Suppressions() {
64*7c3d14c8STreehugger Robot CHECK(suppression_ctx);
65*7c3d14c8STreehugger Robot return suppression_ctx;
66*7c3d14c8STreehugger Robot }
67*7c3d14c8STreehugger Robot
conv(ReportType typ)68*7c3d14c8STreehugger Robot static const char *conv(ReportType typ) {
69*7c3d14c8STreehugger Robot if (typ == ReportTypeRace)
70*7c3d14c8STreehugger Robot return kSuppressionRace;
71*7c3d14c8STreehugger Robot else if (typ == ReportTypeVptrRace)
72*7c3d14c8STreehugger Robot return kSuppressionRace;
73*7c3d14c8STreehugger Robot else if (typ == ReportTypeUseAfterFree)
74*7c3d14c8STreehugger Robot return kSuppressionRace;
75*7c3d14c8STreehugger Robot else if (typ == ReportTypeVptrUseAfterFree)
76*7c3d14c8STreehugger Robot return kSuppressionRace;
77*7c3d14c8STreehugger Robot else if (typ == ReportTypeThreadLeak)
78*7c3d14c8STreehugger Robot return kSuppressionThread;
79*7c3d14c8STreehugger Robot else if (typ == ReportTypeMutexDestroyLocked)
80*7c3d14c8STreehugger Robot return kSuppressionMutex;
81*7c3d14c8STreehugger Robot else if (typ == ReportTypeMutexDoubleLock)
82*7c3d14c8STreehugger Robot return kSuppressionMutex;
83*7c3d14c8STreehugger Robot else if (typ == ReportTypeMutexInvalidAccess)
84*7c3d14c8STreehugger Robot return kSuppressionMutex;
85*7c3d14c8STreehugger Robot else if (typ == ReportTypeMutexBadUnlock)
86*7c3d14c8STreehugger Robot return kSuppressionMutex;
87*7c3d14c8STreehugger Robot else if (typ == ReportTypeMutexBadReadLock)
88*7c3d14c8STreehugger Robot return kSuppressionMutex;
89*7c3d14c8STreehugger Robot else if (typ == ReportTypeMutexBadReadUnlock)
90*7c3d14c8STreehugger Robot return kSuppressionMutex;
91*7c3d14c8STreehugger Robot else if (typ == ReportTypeSignalUnsafe)
92*7c3d14c8STreehugger Robot return kSuppressionSignal;
93*7c3d14c8STreehugger Robot else if (typ == ReportTypeErrnoInSignal)
94*7c3d14c8STreehugger Robot return kSuppressionNone;
95*7c3d14c8STreehugger Robot else if (typ == ReportTypeDeadlock)
96*7c3d14c8STreehugger Robot return kSuppressionDeadlock;
97*7c3d14c8STreehugger Robot Printf("ThreadSanitizer: unknown report type %d\n", typ);
98*7c3d14c8STreehugger Robot Die();
99*7c3d14c8STreehugger Robot }
100*7c3d14c8STreehugger Robot
IsSuppressed(const char * stype,const AddressInfo & info,Suppression ** sp)101*7c3d14c8STreehugger Robot static uptr IsSuppressed(const char *stype, const AddressInfo &info,
102*7c3d14c8STreehugger Robot Suppression **sp) {
103*7c3d14c8STreehugger Robot if (suppression_ctx->Match(info.function, stype, sp) ||
104*7c3d14c8STreehugger Robot suppression_ctx->Match(info.file, stype, sp) ||
105*7c3d14c8STreehugger Robot suppression_ctx->Match(info.module, stype, sp)) {
106*7c3d14c8STreehugger Robot VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", (*sp)->templ);
107*7c3d14c8STreehugger Robot atomic_fetch_add(&(*sp)->hit_count, 1, memory_order_relaxed);
108*7c3d14c8STreehugger Robot return info.address;
109*7c3d14c8STreehugger Robot }
110*7c3d14c8STreehugger Robot return 0;
111*7c3d14c8STreehugger Robot }
112*7c3d14c8STreehugger Robot
IsSuppressed(ReportType typ,const ReportStack * stack,Suppression ** sp)113*7c3d14c8STreehugger Robot uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
114*7c3d14c8STreehugger Robot CHECK(suppression_ctx);
115*7c3d14c8STreehugger Robot if (!suppression_ctx->SuppressionCount() || stack == 0 ||
116*7c3d14c8STreehugger Robot !stack->suppressable)
117*7c3d14c8STreehugger Robot return 0;
118*7c3d14c8STreehugger Robot const char *stype = conv(typ);
119*7c3d14c8STreehugger Robot if (0 == internal_strcmp(stype, kSuppressionNone))
120*7c3d14c8STreehugger Robot return 0;
121*7c3d14c8STreehugger Robot for (const SymbolizedStack *frame = stack->frames; frame;
122*7c3d14c8STreehugger Robot frame = frame->next) {
123*7c3d14c8STreehugger Robot uptr pc = IsSuppressed(stype, frame->info, sp);
124*7c3d14c8STreehugger Robot if (pc != 0)
125*7c3d14c8STreehugger Robot return pc;
126*7c3d14c8STreehugger Robot }
127*7c3d14c8STreehugger Robot if (0 == internal_strcmp(stype, kSuppressionRace) && stack->frames != nullptr)
128*7c3d14c8STreehugger Robot return IsSuppressed(kSuppressionRaceTop, stack->frames->info, sp);
129*7c3d14c8STreehugger Robot return 0;
130*7c3d14c8STreehugger Robot }
131*7c3d14c8STreehugger Robot
IsSuppressed(ReportType typ,const ReportLocation * loc,Suppression ** sp)132*7c3d14c8STreehugger Robot uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
133*7c3d14c8STreehugger Robot CHECK(suppression_ctx);
134*7c3d14c8STreehugger Robot if (!suppression_ctx->SuppressionCount() || loc == 0 ||
135*7c3d14c8STreehugger Robot loc->type != ReportLocationGlobal || !loc->suppressable)
136*7c3d14c8STreehugger Robot return 0;
137*7c3d14c8STreehugger Robot const char *stype = conv(typ);
138*7c3d14c8STreehugger Robot if (0 == internal_strcmp(stype, kSuppressionNone))
139*7c3d14c8STreehugger Robot return 0;
140*7c3d14c8STreehugger Robot Suppression *s;
141*7c3d14c8STreehugger Robot const DataInfo &global = loc->global;
142*7c3d14c8STreehugger Robot if (suppression_ctx->Match(global.name, stype, &s) ||
143*7c3d14c8STreehugger Robot suppression_ctx->Match(global.module, stype, &s)) {
144*7c3d14c8STreehugger Robot VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", s->templ);
145*7c3d14c8STreehugger Robot atomic_fetch_add(&s->hit_count, 1, memory_order_relaxed);
146*7c3d14c8STreehugger Robot *sp = s;
147*7c3d14c8STreehugger Robot return global.start;
148*7c3d14c8STreehugger Robot }
149*7c3d14c8STreehugger Robot return 0;
150*7c3d14c8STreehugger Robot }
151*7c3d14c8STreehugger Robot
PrintMatchedSuppressions()152*7c3d14c8STreehugger Robot void PrintMatchedSuppressions() {
153*7c3d14c8STreehugger Robot InternalMmapVector<Suppression *> matched(1);
154*7c3d14c8STreehugger Robot CHECK(suppression_ctx);
155*7c3d14c8STreehugger Robot suppression_ctx->GetMatched(&matched);
156*7c3d14c8STreehugger Robot if (!matched.size())
157*7c3d14c8STreehugger Robot return;
158*7c3d14c8STreehugger Robot int hit_count = 0;
159*7c3d14c8STreehugger Robot for (uptr i = 0; i < matched.size(); i++)
160*7c3d14c8STreehugger Robot hit_count += atomic_load_relaxed(&matched[i]->hit_count);
161*7c3d14c8STreehugger Robot Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count,
162*7c3d14c8STreehugger Robot (int)internal_getpid());
163*7c3d14c8STreehugger Robot for (uptr i = 0; i < matched.size(); i++) {
164*7c3d14c8STreehugger Robot Printf("%d %s:%s\n", atomic_load_relaxed(&matched[i]->hit_count),
165*7c3d14c8STreehugger Robot matched[i]->type, matched[i]->templ);
166*7c3d14c8STreehugger Robot }
167*7c3d14c8STreehugger Robot }
168*7c3d14c8STreehugger Robot } // namespace __tsan
169