1 //===-- tsan_suppressions.cpp ---------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file is a part of ThreadSanitizer (TSan), a race detector.
11 //===----------------------------------------------------------------------===//
13 #include "tsan_suppressions.h"
15 #include "sanitizer_common/sanitizer_common.h"
16 #include "sanitizer_common/sanitizer_libc.h"
17 #include "sanitizer_common/sanitizer_placement_new.h"
18 #include "sanitizer_common/sanitizer_suppressions.h"
19 #include "tsan_flags.h"
20 #include "tsan_mman.h"
21 #include "tsan_platform.h"
25 // Suppressions for true/false positives in standard libraries.
26 static const char *const std_suppressions
=
27 // Libstdc++ 4.4 has data races in std::string.
28 // See http://crbug.com/181502 for an example.
30 "race:^_M_is_leaked$\n"
31 // False positive when using std <thread>.
32 // Happens because we miss atomic synchronization in libstdc++.
33 // See http://llvm.org/bugs/show_bug.cgi?id=17066 for details.
34 "race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n";
36 // Can be overriden in frontend.
37 SANITIZER_WEAK_DEFAULT_IMPL
38 const char *__tsan_default_suppressions() {
45 ALIGNED(64) static char suppression_placeholder
[sizeof(SuppressionContext
)];
46 static SuppressionContext
*suppression_ctx
= nullptr;
47 static const char *kSuppressionTypes
[] = {
48 kSuppressionRace
, kSuppressionRaceTop
, kSuppressionMutex
,
49 kSuppressionThread
, kSuppressionSignal
, kSuppressionLib
,
50 kSuppressionDeadlock
};
52 void InitializeSuppressions() {
53 CHECK_EQ(nullptr, suppression_ctx
);
54 suppression_ctx
= new (suppression_placeholder
)
55 SuppressionContext(kSuppressionTypes
, ARRAY_SIZE(kSuppressionTypes
));
56 suppression_ctx
->ParseFromFile(flags()->suppressions
);
58 suppression_ctx
->Parse(__tsan_default_suppressions());
59 suppression_ctx
->Parse(std_suppressions
);
63 SuppressionContext
*Suppressions() {
64 CHECK(suppression_ctx
);
65 return suppression_ctx
;
68 static const char *conv(ReportType typ
) {
71 case ReportTypeVptrRace
:
72 case ReportTypeUseAfterFree
:
73 case ReportTypeVptrUseAfterFree
:
74 case ReportTypeExternalRace
:
75 return kSuppressionRace
;
76 case ReportTypeThreadLeak
:
77 return kSuppressionThread
;
78 case ReportTypeMutexDestroyLocked
:
79 case ReportTypeMutexDoubleLock
:
80 case ReportTypeMutexInvalidAccess
:
81 case ReportTypeMutexBadUnlock
:
82 case ReportTypeMutexBadReadLock
:
83 case ReportTypeMutexBadReadUnlock
:
84 return kSuppressionMutex
;
85 case ReportTypeSignalUnsafe
:
86 case ReportTypeErrnoInSignal
:
87 return kSuppressionSignal
;
88 case ReportTypeDeadlock
:
89 return kSuppressionDeadlock
;
90 // No default case so compiler warns us if we miss one
92 UNREACHABLE("missing case");
95 static uptr
IsSuppressed(const char *stype
, const AddressInfo
&info
,
97 if (suppression_ctx
->Match(info
.function
, stype
, sp
) ||
98 suppression_ctx
->Match(info
.file
, stype
, sp
) ||
99 suppression_ctx
->Match(info
.module
, stype
, sp
)) {
100 VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", (*sp
)->templ
);
101 atomic_fetch_add(&(*sp
)->hit_count
, 1, memory_order_relaxed
);
107 uptr
IsSuppressed(ReportType typ
, const ReportStack
*stack
, Suppression
**sp
) {
108 CHECK(suppression_ctx
);
109 if (!suppression_ctx
->SuppressionCount() || stack
== 0 ||
110 !stack
->suppressable
)
112 const char *stype
= conv(typ
);
113 if (0 == internal_strcmp(stype
, kSuppressionNone
))
115 for (const SymbolizedStack
*frame
= stack
->frames
; frame
;
116 frame
= frame
->next
) {
117 uptr pc
= IsSuppressed(stype
, frame
->info
, sp
);
121 if (0 == internal_strcmp(stype
, kSuppressionRace
) && stack
->frames
!= nullptr)
122 return IsSuppressed(kSuppressionRaceTop
, stack
->frames
->info
, sp
);
126 uptr
IsSuppressed(ReportType typ
, const ReportLocation
*loc
, Suppression
**sp
) {
127 CHECK(suppression_ctx
);
128 if (!suppression_ctx
->SuppressionCount() || loc
== 0 ||
129 loc
->type
!= ReportLocationGlobal
|| !loc
->suppressable
)
131 const char *stype
= conv(typ
);
132 if (0 == internal_strcmp(stype
, kSuppressionNone
))
135 const DataInfo
&global
= loc
->global
;
136 if (suppression_ctx
->Match(global
.name
, stype
, &s
) ||
137 suppression_ctx
->Match(global
.module
, stype
, &s
)) {
138 VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", s
->templ
);
139 atomic_fetch_add(&s
->hit_count
, 1, memory_order_relaxed
);
146 void PrintMatchedSuppressions() {
147 InternalMmapVector
<Suppression
*> matched
;
148 CHECK(suppression_ctx
);
149 suppression_ctx
->GetMatched(&matched
);
153 for (uptr i
= 0; i
< matched
.size(); i
++)
154 hit_count
+= atomic_load_relaxed(&matched
[i
]->hit_count
);
155 Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count
,
156 (int)internal_getpid());
157 for (uptr i
= 0; i
< matched
.size(); i
++) {
158 Printf("%d %s:%s\n", atomic_load_relaxed(&matched
[i
]->hit_count
),
159 matched
[i
]->type
, matched
[i
]->templ
);
162 } // namespace __tsan