• 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 // Can be overriden in frontend.
25 #ifndef TSAN_GO
__tsan_default_suppressions()26 extern "C" const char *WEAK __tsan_default_suppressions() {
27   return 0;
28 }
29 #endif
30 
31 namespace __tsan {
32 
33 static SuppressionContext* g_ctx;
34 
ReadFile(const char * filename)35 static char *ReadFile(const char *filename) {
36   if (filename == 0 || filename[0] == 0)
37     return 0;
38   InternalScopedBuffer<char> tmp(4*1024);
39   if (filename[0] == '/' || GetPwd() == 0)
40     internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
41   else
42     internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
43   uptr openrv = OpenFile(tmp.data(), false);
44   if (internal_iserror(openrv)) {
45     Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
46                tmp.data());
47     Die();
48   }
49   fd_t fd = openrv;
50   const uptr fsize = internal_filesize(fd);
51   if (fsize == (uptr)-1) {
52     Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
53                tmp.data());
54     Die();
55   }
56   char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
57   if (fsize != internal_read(fd, buf, fsize)) {
58     Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
59                tmp.data());
60     Die();
61   }
62   internal_close(fd);
63   buf[fsize] = 0;
64   return buf;
65 }
66 
InitializeSuppressions()67 void InitializeSuppressions() {
68   ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
69   g_ctx = new(placeholder_) SuppressionContext;
70   const char *supp = ReadFile(flags()->suppressions);
71   g_ctx->Parse(supp);
72 #ifndef TSAN_GO
73   supp = __tsan_default_suppressions();
74   g_ctx->Parse(supp);
75 #endif
76 }
77 
conv(ReportType typ)78 SuppressionType conv(ReportType typ) {
79   if (typ == ReportTypeRace)
80     return SuppressionRace;
81   else if (typ == ReportTypeVptrRace)
82     return SuppressionRace;
83   else if (typ == ReportTypeUseAfterFree)
84     return SuppressionRace;
85   else if (typ == ReportTypeThreadLeak)
86     return SuppressionThread;
87   else if (typ == ReportTypeMutexDestroyLocked)
88     return SuppressionMutex;
89   else if (typ == ReportTypeSignalUnsafe)
90     return SuppressionSignal;
91   else if (typ == ReportTypeErrnoInSignal)
92     return SuppressionNone;
93   Printf("ThreadSanitizer: unknown report type %d\n", typ),
94   Die();
95 }
96 
IsSuppressed(ReportType typ,const ReportStack * stack,Suppression ** sp)97 uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
98   CHECK(g_ctx);
99   if (!g_ctx->SuppressionCount() || stack == 0) return 0;
100   SuppressionType stype = conv(typ);
101   if (stype == SuppressionNone)
102     return 0;
103   Suppression *s;
104   for (const ReportStack *frame = stack; frame; frame = frame->next) {
105     if (g_ctx->Match(frame->func, stype, &s) ||
106         g_ctx->Match(frame->file, stype, &s) ||
107         g_ctx->Match(frame->module, stype, &s)) {
108       DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
109       s->hit_count++;
110       *sp = s;
111       return frame->pc;
112     }
113   }
114   return 0;
115 }
116 
IsSuppressed(ReportType typ,const ReportLocation * loc,Suppression ** sp)117 uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
118   CHECK(g_ctx);
119   if (!g_ctx->SuppressionCount() || loc == 0 ||
120       loc->type != ReportLocationGlobal)
121     return 0;
122   SuppressionType stype = conv(typ);
123   if (stype == SuppressionNone)
124     return 0;
125   Suppression *s;
126   if (g_ctx->Match(loc->name, stype, &s) ||
127       g_ctx->Match(loc->file, stype, &s) ||
128       g_ctx->Match(loc->module, stype, &s)) {
129       DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
130       s->hit_count++;
131       *sp = s;
132       return loc->addr;
133   }
134   return 0;
135 }
136 
PrintMatchedSuppressions()137 void PrintMatchedSuppressions() {
138   CHECK(g_ctx);
139   InternalMmapVector<Suppression *> matched(1);
140   g_ctx->GetMatched(&matched);
141   if (!matched.size())
142     return;
143   int hit_count = 0;
144   for (uptr i = 0; i < matched.size(); i++)
145     hit_count += matched[i]->hit_count;
146   Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count,
147          (int)internal_getpid());
148   for (uptr i = 0; i < matched.size(); i++) {
149     Printf("%d %s:%s\n", matched[i]->hit_count,
150            SuppressionTypeString(matched[i]->type), matched[i]->templ);
151   }
152 }
153 }  // namespace __tsan
154