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