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