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 // Can be overriden in frontend.
     25 #ifndef TSAN_GO
     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 
     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 
     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 
     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 
     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 
    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 
    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