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 extern "C" const char *WEAK
__tsan_default_suppressions() {
42 ALIGNED(64) static char suppression_placeholder
[sizeof(SuppressionContext
)];
43 static SuppressionContext
*suppression_ctx
= nullptr;
44 static const char *kSuppressionTypes
[] = {
45 kSuppressionRace
, kSuppressionRaceTop
, kSuppressionMutex
,
46 kSuppressionThread
, kSuppressionSignal
, kSuppressionLib
,
47 kSuppressionDeadlock
};
49 void InitializeSuppressions() {
50 CHECK_EQ(nullptr, suppression_ctx
);
51 suppression_ctx
= new (suppression_placeholder
) // NOLINT
52 SuppressionContext(kSuppressionTypes
, ARRAY_SIZE(kSuppressionTypes
));
53 suppression_ctx
->ParseFromFile(flags()->suppressions
);
55 suppression_ctx
->Parse(__tsan_default_suppressions());
56 suppression_ctx
->Parse(std_suppressions
);
60 SuppressionContext
*Suppressions() {
61 CHECK(suppression_ctx
);
62 return suppression_ctx
;
65 static const char *conv(ReportType typ
) {
66 if (typ
== ReportTypeRace
)
67 return kSuppressionRace
;
68 else if (typ
== ReportTypeVptrRace
)
69 return kSuppressionRace
;
70 else if (typ
== ReportTypeUseAfterFree
)
71 return kSuppressionRace
;
72 else if (typ
== ReportTypeVptrUseAfterFree
)
73 return kSuppressionRace
;
74 else if (typ
== ReportTypeThreadLeak
)
75 return kSuppressionThread
;
76 else if (typ
== ReportTypeMutexDestroyLocked
)
77 return kSuppressionMutex
;
78 else if (typ
== ReportTypeMutexDoubleLock
)
79 return kSuppressionMutex
;
80 else if (typ
== ReportTypeMutexBadUnlock
)
81 return kSuppressionMutex
;
82 else if (typ
== ReportTypeMutexBadReadLock
)
83 return kSuppressionMutex
;
84 else if (typ
== ReportTypeMutexBadReadUnlock
)
85 return kSuppressionMutex
;
86 else if (typ
== ReportTypeSignalUnsafe
)
87 return kSuppressionSignal
;
88 else if (typ
== ReportTypeErrnoInSignal
)
89 return kSuppressionNone
;
90 else if (typ
== ReportTypeDeadlock
)
91 return kSuppressionDeadlock
;
92 Printf("ThreadSanitizer: unknown report type %d\n", typ
),
96 static uptr
IsSuppressed(const char *stype
, const AddressInfo
&info
,
98 if (suppression_ctx
->Match(info
.function
, stype
, sp
) ||
99 suppression_ctx
->Match(info
.file
, stype
, sp
) ||
100 suppression_ctx
->Match(info
.module
, stype
, sp
)) {
101 VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", (*sp
)->templ
);
102 atomic_fetch_add(&(*sp
)->hit_count
, 1, memory_order_relaxed
);
108 uptr
IsSuppressed(ReportType typ
, const ReportStack
*stack
, Suppression
**sp
) {
109 CHECK(suppression_ctx
);
110 if (!suppression_ctx
->SuppressionCount() || stack
== 0 ||
111 !stack
->suppressable
)
113 const char *stype
= conv(typ
);
114 if (0 == internal_strcmp(stype
, kSuppressionNone
))
116 for (const SymbolizedStack
*frame
= stack
->frames
; frame
;
117 frame
= frame
->next
) {
118 uptr pc
= IsSuppressed(stype
, frame
->info
, sp
);
122 if (0 == internal_strcmp(stype
, kSuppressionRace
) && stack
->frames
!= nullptr)
123 return IsSuppressed(kSuppressionRaceTop
, stack
->frames
->info
, sp
);
127 uptr
IsSuppressed(ReportType typ
, const ReportLocation
*loc
, Suppression
**sp
) {
128 CHECK(suppression_ctx
);
129 if (!suppression_ctx
->SuppressionCount() || loc
== 0 ||
130 loc
->type
!= ReportLocationGlobal
|| !loc
->suppressable
)
132 const char *stype
= conv(typ
);
133 if (0 == internal_strcmp(stype
, kSuppressionNone
))
136 const DataInfo
&global
= loc
->global
;
137 if (suppression_ctx
->Match(global
.name
, stype
, &s
) ||
138 suppression_ctx
->Match(global
.module
, stype
, &s
)) {
139 VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", s
->templ
);
140 atomic_fetch_add(&s
->hit_count
, 1, memory_order_relaxed
);
147 void PrintMatchedSuppressions() {
148 InternalMmapVector
<Suppression
*> matched(1);
149 CHECK(suppression_ctx
);
150 suppression_ctx
->GetMatched(&matched
);
154 for (uptr i
= 0; i
< matched
.size(); i
++)
155 hit_count
+= atomic_load_relaxed(&matched
[i
]->hit_count
);
156 Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count
,
157 (int)internal_getpid());
158 for (uptr i
= 0; i
< matched
.size(); i
++) {
159 Printf("%d %s:%s\n", matched
[i
]->hit_count
, matched
[i
]->type
,
163 } // namespace __tsan