Home | History | Annotate | Download | only in sanitizer_common
      1 //===-- sanitizer_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 // Suppression parsing/matching code shared between TSan and LSan.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "sanitizer_suppressions.h"
     15 
     16 #include "sanitizer_allocator_internal.h"
     17 #include "sanitizer_common.h"
     18 #include "sanitizer_libc.h"
     19 
     20 namespace __sanitizer {
     21 
     22 static const char *const kTypeStrings[SuppressionTypeCount] = {
     23     "none",   "race", "mutex",           "thread",
     24     "signal", "leak", "called_from_lib", "deadlock"};
     25 
     26 bool TemplateMatch(char *templ, const char *str) {
     27   if (str == 0 || str[0] == 0)
     28     return false;
     29   bool start = false;
     30   if (templ && templ[0] == '^') {
     31     start = true;
     32     templ++;
     33   }
     34   bool asterisk = false;
     35   while (templ && templ[0]) {
     36     if (templ[0] == '*') {
     37       templ++;
     38       start = false;
     39       asterisk = true;
     40       continue;
     41     }
     42     if (templ[0] == '$')
     43       return str[0] == 0 || asterisk;
     44     if (str[0] == 0)
     45       return false;
     46     char *tpos = (char*)internal_strchr(templ, '*');
     47     char *tpos1 = (char*)internal_strchr(templ, '$');
     48     if (tpos == 0 || (tpos1 && tpos1 < tpos))
     49       tpos = tpos1;
     50     if (tpos != 0)
     51       tpos[0] = 0;
     52     const char *str0 = str;
     53     const char *spos = internal_strstr(str, templ);
     54     str = spos + internal_strlen(templ);
     55     templ = tpos;
     56     if (tpos)
     57       tpos[0] = tpos == tpos1 ? '$' : '*';
     58     if (spos == 0)
     59       return false;
     60     if (start && spos != str0)
     61       return false;
     62     start = false;
     63     asterisk = false;
     64   }
     65   return true;
     66 }
     67 
     68 bool SuppressionContext::Match(const char *str, SuppressionType type,
     69                                Suppression **s) {
     70   can_parse_ = false;
     71   uptr i;
     72   for (i = 0; i < suppressions_.size(); i++)
     73     if (type == suppressions_[i].type &&
     74         TemplateMatch(suppressions_[i].templ, str))
     75       break;
     76   if (i == suppressions_.size()) return false;
     77   *s = &suppressions_[i];
     78   return true;
     79 }
     80 
     81 static const char *StripPrefix(const char *str, const char *prefix) {
     82   while (str && *str == *prefix) {
     83     str++;
     84     prefix++;
     85   }
     86   if (!*prefix)
     87     return str;
     88   return 0;
     89 }
     90 
     91 void SuppressionContext::Parse(const char *str) {
     92   // Context must not mutate once Match has been called.
     93   CHECK(can_parse_);
     94   const char *line = str;
     95   while (line) {
     96     while (line[0] == ' ' || line[0] == '\t')
     97       line++;
     98     const char *end = internal_strchr(line, '\n');
     99     if (end == 0)
    100       end = line + internal_strlen(line);
    101     if (line != end && line[0] != '#') {
    102       const char *end2 = end;
    103       while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
    104         end2--;
    105       int type;
    106       for (type = 0; type < SuppressionTypeCount; type++) {
    107         const char *next_char = StripPrefix(line, kTypeStrings[type]);
    108         if (next_char && *next_char == ':') {
    109           line = ++next_char;
    110           break;
    111         }
    112       }
    113       if (type == SuppressionTypeCount) {
    114         Printf("%s: failed to parse suppressions\n", SanitizerToolName);
    115         Die();
    116       }
    117       Suppression s;
    118       s.type = static_cast<SuppressionType>(type);
    119       s.templ = (char*)InternalAlloc(end2 - line + 1);
    120       internal_memcpy(s.templ, line, end2 - line);
    121       s.templ[end2 - line] = 0;
    122       s.hit_count = 0;
    123       s.weight = 0;
    124       suppressions_.push_back(s);
    125     }
    126     if (end[0] == 0)
    127       break;
    128     line = end + 1;
    129   }
    130 }
    131 
    132 uptr SuppressionContext::SuppressionCount() const {
    133   return suppressions_.size();
    134 }
    135 
    136 const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
    137   CHECK_LT(i, suppressions_.size());
    138   return &suppressions_[i];
    139 }
    140 
    141 void SuppressionContext::GetMatched(
    142     InternalMmapVector<Suppression *> *matched) {
    143   for (uptr i = 0; i < suppressions_.size(); i++)
    144     if (suppressions_[i].hit_count)
    145       matched->push_back(&suppressions_[i]);
    146 }
    147 
    148 const char *SuppressionTypeString(SuppressionType t) {
    149   CHECK(t < SuppressionTypeCount);
    150   return kTypeStrings[t];
    151 }
    152 
    153 }  // namespace __sanitizer
    154