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