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"
22 // Suppressions for true/false positives in standard libraries.
23 static const char *const std_suppressions
=
24 // Libstdc++ 4.4 has data races in std::string.
25 // See http://crbug.com/181502 for an example.
27 "race:^_M_is_leaked$\n"
28 // False positive when using std <thread>.
29 // Happens because we miss atomic synchronization in libstdc++.
30 // See http://llvm.org/bugs/show_bug.cgi?id=17066 for details.
31 "race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n";
33 // Can be overriden in frontend.
35 extern "C" const char *WEAK
__tsan_default_suppressions() {
42 static SuppressionContext
* g_ctx
;
44 static char *ReadFile(const char *filename
) {
45 if (filename
== 0 || filename
[0] == 0)
47 InternalScopedBuffer
<char> tmp(4*1024);
48 if (filename
[0] == '/' || GetPwd() == 0)
49 internal_snprintf(tmp
.data(), tmp
.size(), "%s", filename
);
51 internal_snprintf(tmp
.data(), tmp
.size(), "%s/%s", GetPwd(), filename
);
52 uptr openrv
= OpenFile(tmp
.data(), false);
53 if (internal_iserror(openrv
)) {
54 Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
59 const uptr fsize
= internal_filesize(fd
);
60 if (fsize
== (uptr
)-1) {
61 Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
65 char *buf
= (char*)internal_alloc(MBlockSuppression
, fsize
+ 1);
66 if (fsize
!= internal_read(fd
, buf
, fsize
)) {
67 Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
76 void InitializeSuppressions() {
77 ALIGNED(64) static char placeholder_
[sizeof(SuppressionContext
)];
78 g_ctx
= new(placeholder_
) SuppressionContext
;
79 const char *supp
= ReadFile(flags()->suppressions
);
82 supp
= __tsan_default_suppressions();
84 g_ctx
->Parse(std_suppressions
);
88 SuppressionContext
*GetSuppressionContext() {
93 SuppressionType
conv(ReportType typ
) {
94 if (typ
== ReportTypeRace
)
95 return SuppressionRace
;
96 else if (typ
== ReportTypeVptrRace
)
97 return SuppressionRace
;
98 else if (typ
== ReportTypeUseAfterFree
)
99 return SuppressionRace
;
100 else if (typ
== ReportTypeThreadLeak
)
101 return SuppressionThread
;
102 else if (typ
== ReportTypeMutexDestroyLocked
)
103 return SuppressionMutex
;
104 else if (typ
== ReportTypeMutexDoubleLock
)
105 return SuppressionMutex
;
106 else if (typ
== ReportTypeMutexBadUnlock
)
107 return SuppressionMutex
;
108 else if (typ
== ReportTypeMutexBadReadLock
)
109 return SuppressionMutex
;
110 else if (typ
== ReportTypeMutexBadReadUnlock
)
111 return SuppressionMutex
;
112 else if (typ
== ReportTypeSignalUnsafe
)
113 return SuppressionSignal
;
114 else if (typ
== ReportTypeErrnoInSignal
)
115 return SuppressionNone
;
116 else if (typ
== ReportTypeDeadlock
)
117 return SuppressionDeadlock
;
118 Printf("ThreadSanitizer: unknown report type %d\n", typ
),
122 uptr
IsSuppressed(ReportType typ
, const ReportStack
*stack
, Suppression
**sp
) {
124 if (!g_ctx
->SuppressionCount() || stack
== 0) return 0;
125 SuppressionType stype
= conv(typ
);
126 if (stype
== SuppressionNone
)
129 for (const ReportStack
*frame
= stack
; frame
; frame
= frame
->next
) {
130 if (g_ctx
->Match(frame
->func
, stype
, &s
) ||
131 g_ctx
->Match(frame
->file
, stype
, &s
) ||
132 g_ctx
->Match(frame
->module
, stype
, &s
)) {
133 DPrintf("ThreadSanitizer: matched suppression '%s'\n", s
->templ
);
142 uptr
IsSuppressed(ReportType typ
, const ReportLocation
*loc
, Suppression
**sp
) {
144 if (!g_ctx
->SuppressionCount() || loc
== 0 ||
145 loc
->type
!= ReportLocationGlobal
)
147 SuppressionType stype
= conv(typ
);
148 if (stype
== SuppressionNone
)
151 if (g_ctx
->Match(loc
->name
, stype
, &s
) ||
152 g_ctx
->Match(loc
->file
, stype
, &s
) ||
153 g_ctx
->Match(loc
->module
, stype
, &s
)) {
154 DPrintf("ThreadSanitizer: matched suppression '%s'\n", s
->templ
);
162 void PrintMatchedSuppressions() {
164 InternalMmapVector
<Suppression
*> matched(1);
165 g_ctx
->GetMatched(&matched
);
169 for (uptr i
= 0; i
< matched
.size(); i
++)
170 hit_count
+= matched
[i
]->hit_count
;
171 Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count
,
172 (int)internal_getpid());
173 for (uptr i
= 0; i
< matched
.size(); i
++) {
174 Printf("%d %s:%s\n", matched
[i
]->hit_count
,
175 SuppressionTypeString(matched
[i
]->type
), matched
[i
]->templ
);
178 } // namespace __tsan