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 "tsan_suppressions.h"
     17 #include "tsan_rtl.h"
     18 #include "tsan_flags.h"
     19 #include "tsan_mman.h"
     20 #include "tsan_platform.h"
     21 
     22 // Can be overriden in frontend.
     23 #ifndef TSAN_GO
     24 extern "C" const char *WEAK __tsan_default_suppressions() {
     25   return 0;
     26 }
     27 #endif
     28 
     29 namespace __tsan {
     30 
     31 static Suppression *g_suppressions;
     32 
     33 static char *ReadFile(const char *filename) {
     34   if (filename == 0 || filename[0] == 0)
     35     return 0;
     36   InternalScopedBuffer<char> tmp(4*1024);
     37   if (filename[0] == '/' || GetPwd() == 0)
     38     internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
     39   else
     40     internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
     41   fd_t fd = OpenFile(tmp.data(), false);
     42   if (fd == kInvalidFd) {
     43     Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
     44                tmp.data());
     45     Die();
     46   }
     47   const uptr fsize = internal_filesize(fd);
     48   if (fsize == (uptr)-1) {
     49     Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
     50                tmp.data());
     51     Die();
     52   }
     53   char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
     54   if (fsize != internal_read(fd, buf, fsize)) {
     55     Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
     56                tmp.data());
     57     Die();
     58   }
     59   internal_close(fd);
     60   buf[fsize] = 0;
     61   return buf;
     62 }
     63 
     64 bool SuppressionMatch(char *templ, const char *str) {
     65   if (str == 0 || str[0] == 0)
     66     return false;
     67   char *tpos;
     68   const char *spos;
     69   while (templ && templ[0]) {
     70     if (templ[0] == '*') {
     71       templ++;
     72       continue;
     73     }
     74     if (str[0] == 0)
     75       return false;
     76     tpos = (char*)internal_strchr(templ, '*');
     77     if (tpos != 0)
     78       tpos[0] = 0;
     79     spos = internal_strstr(str, templ);
     80     str = spos + internal_strlen(templ);
     81     templ = tpos;
     82     if (tpos)
     83       tpos[0] = '*';
     84     if (spos == 0)
     85       return false;
     86   }
     87   return true;
     88 }
     89 
     90 Suppression *SuppressionParse(Suppression *head, const char* supp) {
     91   const char *line = supp;
     92   while (line) {
     93     while (line[0] == ' ' || line[0] == '\t')
     94       line++;
     95     const char *end = internal_strchr(line, '\n');
     96     if (end == 0)
     97       end = line + internal_strlen(line);
     98     if (line != end && line[0] != '#') {
     99       const char *end2 = end;
    100       while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
    101         end2--;
    102       SuppressionType stype;
    103       if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) {
    104         stype = SuppressionRace;
    105         line += sizeof("race:") - 1;
    106       } else if (0 == internal_strncmp(line, "thread:",
    107           sizeof("thread:") - 1)) {
    108         stype = SuppressionThread;
    109         line += sizeof("thread:") - 1;
    110       } else if (0 == internal_strncmp(line, "mutex:",
    111           sizeof("mutex:") - 1)) {
    112         stype = SuppressionMutex;
    113         line += sizeof("mutex:") - 1;
    114       } else if (0 == internal_strncmp(line, "signal:",
    115           sizeof("signal:") - 1)) {
    116         stype = SuppressionSignal;
    117         line += sizeof("signal:") - 1;
    118       } else {
    119         Printf("ThreadSanitizer: failed to parse suppressions file\n");
    120         Die();
    121       }
    122       Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
    123           sizeof(Suppression));
    124       s->next = head;
    125       head = s;
    126       s->type = stype;
    127       s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
    128       internal_memcpy(s->templ, line, end2 - line);
    129       s->templ[end2 - line] = 0;
    130     }
    131     if (end[0] == 0)
    132       break;
    133     line = end + 1;
    134   }
    135   return head;
    136 }
    137 
    138 void InitializeSuppressions() {
    139   const char *supp = ReadFile(flags()->suppressions);
    140   g_suppressions = SuppressionParse(0, supp);
    141 #ifndef TSAN_GO
    142   supp = __tsan_default_suppressions();
    143   g_suppressions = SuppressionParse(g_suppressions, supp);
    144 #endif
    145 }
    146 
    147 uptr IsSuppressed(ReportType typ, const ReportStack *stack) {
    148   if (g_suppressions == 0 || stack == 0)
    149     return 0;
    150   SuppressionType stype;
    151   if (typ == ReportTypeRace)
    152     stype = SuppressionRace;
    153   else if (typ == ReportTypeThreadLeak)
    154     stype = SuppressionThread;
    155   else if (typ == ReportTypeMutexDestroyLocked)
    156     stype = SuppressionMutex;
    157   else if (typ == ReportTypeSignalUnsafe)
    158     stype = SuppressionSignal;
    159   else
    160     return 0;
    161   for (const ReportStack *frame = stack; frame; frame = frame->next) {
    162     for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
    163       if (stype == supp->type &&
    164           (SuppressionMatch(supp->templ, frame->func) ||
    165            SuppressionMatch(supp->templ, frame->file) ||
    166            SuppressionMatch(supp->templ, frame->module))) {
    167         DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
    168         return frame->pc;
    169       }
    170     }
    171   }
    172   return 0;
    173 }
    174 }  // namespace __tsan
    175