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 (ReadBinaryName(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 char *file_contents; 64 uptr buffer_size; 65 const uptr max_len = 1 << 26; 66 uptr contents_size = 67 ReadFileToBuffer(filename, &file_contents, &buffer_size, max_len); 68 VPrintf(1, "%s: reading suppressions file at %s\n", 69 SanitizerToolName, filename); 70 71 if (contents_size == 0) { 72 Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName, 73 filename); 74 Die(); 75 } 76 77 Parse(file_contents); 78 } 79 80 bool SuppressionContext::Match(const char *str, const char *type, 81 Suppression **s) { 82 can_parse_ = false; 83 if (!HasSuppressionType(type)) 84 return false; 85 for (uptr i = 0; i < suppressions_.size(); i++) { 86 Suppression &cur = suppressions_[i]; 87 if (0 == internal_strcmp(cur.type, type) && TemplateMatch(cur.templ, str)) { 88 *s = &cur; 89 return true; 90 } 91 } 92 return false; 93 } 94 95 static const char *StripPrefix(const char *str, const char *prefix) { 96 while (str && *str == *prefix) { 97 str++; 98 prefix++; 99 } 100 if (!*prefix) 101 return str; 102 return 0; 103 } 104 105 void SuppressionContext::Parse(const char *str) { 106 // Context must not mutate once Match has been called. 107 CHECK(can_parse_); 108 const char *line = str; 109 while (line) { 110 while (line[0] == ' ' || line[0] == '\t') 111 line++; 112 const char *end = internal_strchr(line, '\n'); 113 if (end == 0) 114 end = line + internal_strlen(line); 115 if (line != end && line[0] != '#') { 116 const char *end2 = end; 117 while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t')) 118 end2--; 119 int type; 120 for (type = 0; type < suppression_types_num_; type++) { 121 const char *next_char = StripPrefix(line, suppression_types_[type]); 122 if (next_char && *next_char == ':') { 123 line = ++next_char; 124 break; 125 } 126 } 127 if (type == suppression_types_num_) { 128 Printf("%s: failed to parse suppressions\n", SanitizerToolName); 129 Die(); 130 } 131 Suppression s; 132 s.type = suppression_types_[type]; 133 s.templ = (char*)InternalAlloc(end2 - line + 1); 134 internal_memcpy(s.templ, line, end2 - line); 135 s.templ[end2 - line] = 0; 136 s.hit_count = 0; 137 s.weight = 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 (suppressions_[i].hit_count) 168 matched->push_back(&suppressions_[i]); 169 } 170 171 } // namespace __sanitizer 172