Home | History | Annotate | Download | only in rtl
      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
     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 
     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 
     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 
     90 SuppressionContext *GetSuppressionContext() {
     91   CHECK_NE(g_ctx, 0);
     92   return g_ctx;
     93 }
     94 
     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 
    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 
    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 
    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