1 //===-- tsan_suppressions.cc ----------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
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"
18 #include "tsan_flags.h"
19 #include "tsan_mman.h"
20 #include "tsan_platform.h"
23 // Suppressions for true/false positives in standard libraries.
24 static const char *const std_suppressions
=
25 // Libstdc++ 4.4 has data races in std::string.
26 // See http://crbug.com/181502 for an example.
28 "race:^_M_is_leaked$\n"
29 // False positive when using std <thread>.
30 // Happens because we miss atomic synchronization in libstdc++.
31 // See http://llvm.org/bugs/show_bug.cgi?id=17066 for details.
32 "race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n";
34 // Can be overriden in frontend.
35 SANITIZER_WEAK_DEFAULT_IMPL
36 const char *__tsan_default_suppressions() {
43 ALIGNED(64) static char suppression_placeholder
[sizeof(SuppressionContext
)];
44 static SuppressionContext
*suppression_ctx
= nullptr;
45 static const char *kSuppressionTypes
[] = {
46 kSuppressionRace
, kSuppressionRaceTop
, kSuppressionMutex
,
47 kSuppressionThread
, kSuppressionSignal
, kSuppressionLib
,
48 kSuppressionDeadlock
};
50 void InitializeSuppressions() {
51 CHECK_EQ(nullptr, suppression_ctx
);
52 suppression_ctx
= new (suppression_placeholder
) // NOLINT
53 SuppressionContext(kSuppressionTypes
, ARRAY_SIZE(kSuppressionTypes
));
54 suppression_ctx
->ParseFromFile(flags()->suppressions
);
56 suppression_ctx
->Parse(__tsan_default_suppressions());
57 suppression_ctx
->Parse(std_suppressions
);
61 SuppressionContext
*Suppressions() {
62 CHECK(suppression_ctx
);
63 return suppression_ctx
;
66 static const char *conv(ReportType typ
) {
67 if (typ
== ReportTypeRace
)
68 return kSuppressionRace
;
69 else if (typ
== ReportTypeVptrRace
)
70 return kSuppressionRace
;
71 else if (typ
== ReportTypeUseAfterFree
)
72 return kSuppressionRace
;
73 else if (typ
== ReportTypeVptrUseAfterFree
)
74 return kSuppressionRace
;
75 else if (typ
== ReportTypeThreadLeak
)
76 return kSuppressionThread
;
77 else if (typ
== ReportTypeMutexDestroyLocked
)
78 return kSuppressionMutex
;
79 else if (typ
== ReportTypeMutexDoubleLock
)
80 return kSuppressionMutex
;
81 else if (typ
== ReportTypeMutexInvalidAccess
)
82 return kSuppressionMutex
;
83 else if (typ
== ReportTypeMutexBadUnlock
)
84 return kSuppressionMutex
;
85 else if (typ
== ReportTypeMutexBadReadLock
)
86 return kSuppressionMutex
;
87 else if (typ
== ReportTypeMutexBadReadUnlock
)
88 return kSuppressionMutex
;
89 else if (typ
== ReportTypeSignalUnsafe
)
90 return kSuppressionSignal
;
91 else if (typ
== ReportTypeErrnoInSignal
)
92 return kSuppressionNone
;
93 else if (typ
== ReportTypeDeadlock
)
94 return kSuppressionDeadlock
;
95 Printf("ThreadSanitizer: unknown report type %d\n", typ
);
99 static uptr
IsSuppressed(const char *stype
, const AddressInfo
&info
,
101 if (suppression_ctx
->Match(info
.function
, stype
, sp
) ||
102 suppression_ctx
->Match(info
.file
, stype
, sp
) ||
103 suppression_ctx
->Match(info
.module
, stype
, sp
)) {
104 VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", (*sp
)->templ
);
105 atomic_fetch_add(&(*sp
)->hit_count
, 1, memory_order_relaxed
);
111 uptr
IsSuppressed(ReportType typ
, const ReportStack
*stack
, Suppression
**sp
) {
112 CHECK(suppression_ctx
);
113 if (!suppression_ctx
->SuppressionCount() || stack
== 0 ||
114 !stack
->suppressable
)
116 const char *stype
= conv(typ
);
117 if (0 == internal_strcmp(stype
, kSuppressionNone
))
119 for (const SymbolizedStack
*frame
= stack
->frames
; frame
;
120 frame
= frame
->next
) {
121 uptr pc
= IsSuppressed(stype
, frame
->info
, sp
);
125 if (0 == internal_strcmp(stype
, kSuppressionRace
) && stack
->frames
!= nullptr)
126 return IsSuppressed(kSuppressionRaceTop
, stack
->frames
->info
, sp
);
130 uptr
IsSuppressed(ReportType typ
, const ReportLocation
*loc
, Suppression
**sp
) {
131 CHECK(suppression_ctx
);
132 if (!suppression_ctx
->SuppressionCount() || loc
== 0 ||
133 loc
->type
!= ReportLocationGlobal
|| !loc
->suppressable
)
135 const char *stype
= conv(typ
);
136 if (0 == internal_strcmp(stype
, kSuppressionNone
))
139 const DataInfo
&global
= loc
->global
;
140 if (suppression_ctx
->Match(global
.name
, stype
, &s
) ||
141 suppression_ctx
->Match(global
.module
, stype
, &s
)) {
142 VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", s
->templ
);
143 atomic_fetch_add(&s
->hit_count
, 1, memory_order_relaxed
);
150 void PrintMatchedSuppressions() {
151 InternalMmapVector
<Suppression
*> matched(1);
152 CHECK(suppression_ctx
);
153 suppression_ctx
->GetMatched(&matched
);
157 for (uptr i
= 0; i
< matched
.size(); i
++)
158 hit_count
+= atomic_load_relaxed(&matched
[i
]->hit_count
);
159 Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count
,
160 (int)internal_getpid());
161 for (uptr i
= 0; i
< matched
.size(); i
++) {
162 Printf("%d %s:%s\n", atomic_load_relaxed(&matched
[i
]->hit_count
),
163 matched
[i
]->type
, matched
[i
]->templ
);
166 } // namespace __tsan