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 "sanitizer_common/sanitizer_common.h"
14 #include "sanitizer_common/sanitizer_libc.h"
15 #include "sanitizer_common/sanitizer_placement_new.h"
16 #include "sanitizer_common/sanitizer_suppressions.h"
17 #include "tsan_suppressions.h"
19 #include "tsan_flags.h"
20 #include "tsan_mman.h"
21 #include "tsan_platform.h"
24 // Suppressions for true/false positives in standard libraries.
25 static const char *const std_suppressions
=
26 // Libstdc++ 4.4 has data races in std::string.
27 // See http://crbug.com/181502 for an example.
29 "race:^_M_is_leaked$\n"
30 // False positive when using std <thread>.
31 // Happens because we miss atomic synchronization in libstdc++.
32 // See http://llvm.org/bugs/show_bug.cgi?id=17066 for details.
33 "race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n";
35 // Can be overriden in frontend.
36 SANITIZER_WEAK_DEFAULT_IMPL
37 const char *__tsan_default_suppressions() {
44 ALIGNED(64) static char suppression_placeholder
[sizeof(SuppressionContext
)];
45 static SuppressionContext
*suppression_ctx
= nullptr;
46 static const char *kSuppressionTypes
[] = {
47 kSuppressionRace
, kSuppressionRaceTop
, kSuppressionMutex
,
48 kSuppressionThread
, kSuppressionSignal
, kSuppressionLib
,
49 kSuppressionDeadlock
};
51 void InitializeSuppressions() {
52 CHECK_EQ(nullptr, suppression_ctx
);
53 suppression_ctx
= new (suppression_placeholder
)
54 SuppressionContext(kSuppressionTypes
, ARRAY_SIZE(kSuppressionTypes
));
55 suppression_ctx
->ParseFromFile(flags()->suppressions
);
57 suppression_ctx
->Parse(__tsan_default_suppressions());
58 suppression_ctx
->Parse(std_suppressions
);
62 SuppressionContext
*Suppressions() {
63 CHECK(suppression_ctx
);
64 return suppression_ctx
;
67 static const char *conv(ReportType typ
) {
70 case ReportTypeVptrRace
:
71 case ReportTypeUseAfterFree
:
72 case ReportTypeVptrUseAfterFree
:
73 case ReportTypeExternalRace
:
74 return kSuppressionRace
;
75 case ReportTypeThreadLeak
:
76 return kSuppressionThread
;
77 case ReportTypeMutexDestroyLocked
:
78 case ReportTypeMutexDoubleLock
:
79 case ReportTypeMutexInvalidAccess
:
80 case ReportTypeMutexBadUnlock
:
81 case ReportTypeMutexBadReadLock
:
82 case ReportTypeMutexBadReadUnlock
:
83 return kSuppressionMutex
;
84 case ReportTypeSignalUnsafe
:
85 case ReportTypeErrnoInSignal
:
86 return kSuppressionSignal
;
87 case ReportTypeDeadlock
:
88 return kSuppressionDeadlock
;
89 // No default case so compiler warns us if we miss one
91 UNREACHABLE("missing case");
94 static uptr
IsSuppressed(const char *stype
, const AddressInfo
&info
,
96 if (suppression_ctx
->Match(info
.function
, stype
, sp
) ||
97 suppression_ctx
->Match(info
.file
, stype
, sp
) ||
98 suppression_ctx
->Match(info
.module
, stype
, sp
)) {
99 VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", (*sp
)->templ
);
100 atomic_fetch_add(&(*sp
)->hit_count
, 1, memory_order_relaxed
);
106 uptr
IsSuppressed(ReportType typ
, const ReportStack
*stack
, Suppression
**sp
) {
107 CHECK(suppression_ctx
);
108 if (!suppression_ctx
->SuppressionCount() || stack
== 0 ||
109 !stack
->suppressable
)
111 const char *stype
= conv(typ
);
112 if (0 == internal_strcmp(stype
, kSuppressionNone
))
114 for (const SymbolizedStack
*frame
= stack
->frames
; frame
;
115 frame
= frame
->next
) {
116 uptr pc
= IsSuppressed(stype
, frame
->info
, sp
);
120 if (0 == internal_strcmp(stype
, kSuppressionRace
) && stack
->frames
!= nullptr)
121 return IsSuppressed(kSuppressionRaceTop
, stack
->frames
->info
, sp
);
125 uptr
IsSuppressed(ReportType typ
, const ReportLocation
*loc
, Suppression
**sp
) {
126 CHECK(suppression_ctx
);
127 if (!suppression_ctx
->SuppressionCount() || loc
== 0 ||
128 loc
->type
!= ReportLocationGlobal
|| !loc
->suppressable
)
130 const char *stype
= conv(typ
);
131 if (0 == internal_strcmp(stype
, kSuppressionNone
))
134 const DataInfo
&global
= loc
->global
;
135 if (suppression_ctx
->Match(global
.name
, stype
, &s
) ||
136 suppression_ctx
->Match(global
.module
, stype
, &s
)) {
137 VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", s
->templ
);
138 atomic_fetch_add(&s
->hit_count
, 1, memory_order_relaxed
);
145 void PrintMatchedSuppressions() {
146 InternalMmapVector
<Suppression
*> matched
;
147 CHECK(suppression_ctx
);
148 suppression_ctx
->GetMatched(&matched
);
152 for (uptr i
= 0; i
< matched
.size(); i
++)
153 hit_count
+= atomic_load_relaxed(&matched
[i
]->hit_count
);
154 Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count
,
155 (int)internal_getpid());
156 for (uptr i
= 0; i
< matched
.size(); i
++) {
157 Printf("%d %s:%s\n", atomic_load_relaxed(&matched
[i
]->hit_count
),
158 matched
[i
]->type
, matched
[i
]->templ
);
161 } // namespace __tsan