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.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "sanitizer_suppressions.h"
     15 
     16 #include "sanitizer_allocator_internal.h"
     17 #include "sanitizer_common.h"
     18 #include "sanitizer_flags.h"
     19 #include "sanitizer_libc.h"
     20 #include "sanitizer_placement_new.h"
     21 
     22 namespace __sanitizer {
     23 
     24 SuppressionContext::SuppressionContext(const char *suppression_types[],
     25                                        int suppression_types_num)
     26     : suppression_types_(suppression_types),
     27       suppression_types_num_(suppression_types_num), suppressions_(1),
     28       can_parse_(true) {
     29   CHECK_LE(suppression_types_num_, kMaxSuppressionTypes);
     30   internal_memset(has_suppression_type_, 0, suppression_types_num_);
     31 }
     32 
     33 static bool GetPathAssumingFileIsRelativeToExec(const char *file_path,
     34                                                 /*out*/char *new_file_path,
     35                                                 uptr new_file_path_size) {
     36   InternalScopedString exec(kMaxPathLength);
     37   if (ReadBinaryNameCached(exec.data(), exec.size())) {
     38     const char *file_name_pos = StripModuleName(exec.data());
     39     uptr path_to_exec_len = file_name_pos - exec.data();
     40     internal_strncat(new_file_path, exec.data(),
     41                      Min(path_to_exec_len, new_file_path_size - 1));
     42     internal_strncat(new_file_path, file_path,
     43                      new_file_path_size - internal_strlen(new_file_path) - 1);
     44     return true;
     45   }
     46   return false;
     47 }
     48 
     49 void SuppressionContext::ParseFromFile(const char *filename) {
     50   if (filename[0] == '\0')
     51     return;
     52 
     53   // If we cannot find the file, check if its location is relative to
     54   // the location of the executable.
     55   InternalScopedString new_file_path(kMaxPathLength);
     56   if (!FileExists(filename) && !IsAbsolutePath(filename) &&
     57       GetPathAssumingFileIsRelativeToExec(filename, new_file_path.data(),
     58                                           new_file_path.size())) {
     59     filename = new_file_path.data();
     60   }
     61 
     62   // Read the file.
     63   VPrintf(1, "%s: reading suppressions file at %s\n",
     64           SanitizerToolName, filename);
     65   char *file_contents;
     66   uptr buffer_size;
     67   uptr contents_size;
     68   if (!ReadFileToBuffer(filename, &file_contents, &buffer_size,
     69                         &contents_size)) {
     70     Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
     71            filename);
     72     Die();
     73   }
     74 
     75   Parse(file_contents);
     76 }
     77 
     78 bool SuppressionContext::Match(const char *str, const char *type,
     79                                Suppression **s) {
     80   can_parse_ = false;
     81   if (!HasSuppressionType(type))
     82     return false;
     83   for (uptr i = 0; i < suppressions_.size(); i++) {
     84     Suppression &cur = suppressions_[i];
     85     if (0 == internal_strcmp(cur.type, type) && TemplateMatch(cur.templ, str)) {
     86       *s = &cur;
     87       return true;
     88     }
     89   }
     90   return false;
     91 }
     92 
     93 static const char *StripPrefix(const char *str, const char *prefix) {
     94   while (str && *str == *prefix) {
     95     str++;
     96     prefix++;
     97   }
     98   if (!*prefix)
     99     return str;
    100   return 0;
    101 }
    102 
    103 void SuppressionContext::Parse(const char *str) {
    104   // Context must not mutate once Match has been called.
    105   CHECK(can_parse_);
    106   const char *line = str;
    107   while (line) {
    108     while (line[0] == ' ' || line[0] == '\t')
    109       line++;
    110     const char *end = internal_strchr(line, '\n');
    111     if (end == 0)
    112       end = line + internal_strlen(line);
    113     if (line != end && line[0] != '#') {
    114       const char *end2 = end;
    115       while (line != end2 &&
    116              (end2[-1] == ' ' || end2[-1] == '\t' || end2[-1] == '\r'))
    117         end2--;
    118       int type;
    119       for (type = 0; type < suppression_types_num_; type++) {
    120         const char *next_char = StripPrefix(line, suppression_types_[type]);
    121         if (next_char && *next_char == ':') {
    122           line = ++next_char;
    123           break;
    124         }
    125       }
    126       if (type == suppression_types_num_) {
    127         Printf("%s: failed to parse suppressions\n", SanitizerToolName);
    128         Die();
    129       }
    130       Suppression s;
    131       s.type = suppression_types_[type];
    132       s.templ = (char*)InternalAlloc(end2 - line + 1);
    133       internal_memcpy(s.templ, line, end2 - line);
    134       s.templ[end2 - line] = 0;
    135       suppressions_.push_back(s);
    136       has_suppression_type_[type] = true;
    137     }
    138     if (end[0] == 0)
    139       break;
    140     line = end + 1;
    141   }
    142 }
    143 
    144 uptr SuppressionContext::SuppressionCount() const {
    145   return suppressions_.size();
    146 }
    147 
    148 bool SuppressionContext::HasSuppressionType(const char *type) const {
    149   for (int i = 0; i < suppression_types_num_; i++) {
    150     if (0 == internal_strcmp(type, suppression_types_[i]))
    151       return has_suppression_type_[i];
    152   }
    153   return false;
    154 }
    155 
    156 const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
    157   CHECK_LT(i, suppressions_.size());
    158   return &suppressions_[i];
    159 }
    160 
    161 void SuppressionContext::GetMatched(
    162     InternalMmapVector<Suppression *> *matched) {
    163   for (uptr i = 0; i < suppressions_.size(); i++)
    164     if (atomic_load_relaxed(&suppressions_[i].hit_count))
    165       matched->push_back(&suppressions_[i]);
    166 }
    167 
    168 }  // namespace __sanitizer
    169