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