• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- tsan_suppressions.cc ----------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file is a part of ThreadSanitizer (TSan), a race detector.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "sanitizer_common/sanitizer_common.h"
15 #include "sanitizer_common/sanitizer_libc.h"
16 #include "sanitizer_common/sanitizer_placement_new.h"
17 #include "sanitizer_common/sanitizer_suppressions.h"
18 #include "tsan_suppressions.h"
19 #include "tsan_rtl.h"
20 #include "tsan_flags.h"
21 #include "tsan_mman.h"
22 #include "tsan_platform.h"
23 
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.
28 "race:^_M_rep$\n"
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";
34 
35 // Can be overriden in frontend.
36 #ifndef TSAN_GO
__tsan_default_suppressions()37 extern "C" const char *WEAK __tsan_default_suppressions() {
38   return 0;
39 }
40 #endif
41 
42 namespace __tsan {
43 
44 static SuppressionContext* g_ctx;
45 
ReadFile(const char * filename)46 static char *ReadFile(const char *filename) {
47   if (filename == 0 || filename[0] == 0)
48     return 0;
49   InternalScopedBuffer<char> tmp(4*1024);
50   if (filename[0] == '/' || GetPwd() == 0)
51     internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
52   else
53     internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
54   uptr openrv = OpenFile(tmp.data(), false);
55   if (internal_iserror(openrv)) {
56     Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
57                tmp.data());
58     Die();
59   }
60   fd_t fd = openrv;
61   const uptr fsize = internal_filesize(fd);
62   if (fsize == (uptr)-1) {
63     Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
64                tmp.data());
65     Die();
66   }
67   char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
68   if (fsize != internal_read(fd, buf, fsize)) {
69     Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
70                tmp.data());
71     Die();
72   }
73   internal_close(fd);
74   buf[fsize] = 0;
75   return buf;
76 }
77 
InitializeSuppressions()78 void InitializeSuppressions() {
79   ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
80   g_ctx = new(placeholder_) SuppressionContext;
81   const char *supp = ReadFile(flags()->suppressions);
82   g_ctx->Parse(supp);
83 #ifndef TSAN_GO
84   supp = __tsan_default_suppressions();
85   g_ctx->Parse(supp);
86   g_ctx->Parse(std_suppressions);
87 #endif
88 }
89 
GetSuppressionContext()90 SuppressionContext *GetSuppressionContext() {
91   CHECK_NE(g_ctx, 0);
92   return g_ctx;
93 }
94 
conv(ReportType typ)95 SuppressionType conv(ReportType typ) {
96   if (typ == ReportTypeRace)
97     return SuppressionRace;
98   else if (typ == ReportTypeVptrRace)
99     return SuppressionRace;
100   else if (typ == ReportTypeUseAfterFree)
101     return SuppressionRace;
102   else if (typ == ReportTypeThreadLeak)
103     return SuppressionThread;
104   else if (typ == ReportTypeMutexDestroyLocked)
105     return SuppressionMutex;
106   else if (typ == ReportTypeMutexDoubleLock)
107     return SuppressionMutex;
108   else if (typ == ReportTypeMutexBadUnlock)
109     return SuppressionMutex;
110   else if (typ == ReportTypeMutexBadReadLock)
111     return SuppressionMutex;
112   else if (typ == ReportTypeMutexBadReadUnlock)
113     return SuppressionMutex;
114   else if (typ == ReportTypeSignalUnsafe)
115     return SuppressionSignal;
116   else if (typ == ReportTypeErrnoInSignal)
117     return SuppressionNone;
118   else if (typ == ReportTypeDeadlock)
119     return SuppressionDeadlock;
120   Printf("ThreadSanitizer: unknown report type %d\n", typ),
121   Die();
122 }
123 
IsSuppressed(ReportType typ,const ReportStack * stack,Suppression ** sp)124 uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
125   CHECK(g_ctx);
126   if (!g_ctx->SuppressionCount() || stack == 0 || !stack->suppressable)
127     return 0;
128   SuppressionType stype = conv(typ);
129   if (stype == SuppressionNone)
130     return 0;
131   Suppression *s;
132   for (const ReportStack *frame = stack; frame; frame = frame->next) {
133     if (g_ctx->Match(frame->func, stype, &s) ||
134         g_ctx->Match(frame->file, stype, &s) ||
135         g_ctx->Match(frame->module, stype, &s)) {
136       DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
137       s->hit_count++;
138       *sp = s;
139       return frame->pc;
140     }
141   }
142   return 0;
143 }
144 
IsSuppressed(ReportType typ,const ReportLocation * loc,Suppression ** sp)145 uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
146   CHECK(g_ctx);
147   if (!g_ctx->SuppressionCount() || loc == 0 ||
148       loc->type != ReportLocationGlobal || !loc->suppressable)
149     return 0;
150   SuppressionType stype = conv(typ);
151   if (stype == SuppressionNone)
152     return 0;
153   Suppression *s;
154   if (g_ctx->Match(loc->name, stype, &s) ||
155       g_ctx->Match(loc->file, stype, &s) ||
156       g_ctx->Match(loc->module, stype, &s)) {
157       DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
158       s->hit_count++;
159       *sp = s;
160       return loc->addr;
161   }
162   return 0;
163 }
164 
PrintMatchedSuppressions()165 void PrintMatchedSuppressions() {
166   CHECK(g_ctx);
167   InternalMmapVector<Suppression *> matched(1);
168   g_ctx->GetMatched(&matched);
169   if (!matched.size())
170     return;
171   int hit_count = 0;
172   for (uptr i = 0; i < matched.size(); i++)
173     hit_count += matched[i]->hit_count;
174   Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count,
175          (int)internal_getpid());
176   for (uptr i = 0; i < matched.size(); i++) {
177     Printf("%d %s:%s\n", matched[i]->hit_count,
178            SuppressionTypeString(matched[i]->type), matched[i]->templ);
179   }
180 }
181 }  // namespace __tsan
182