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 shared between TSan and LSan. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "sanitizer_suppressions.h" 15 16 #include "sanitizer_allocator_internal.h" 17 #include "sanitizer_common.h" 18 #include "sanitizer_libc.h" 19 20 namespace __sanitizer { 21 22 static const char *const kTypeStrings[SuppressionTypeCount] = { 23 "none", "race", "mutex", "thread", "signal", "leak" 24 }; 25 26 bool TemplateMatch(char *templ, const char *str) { 27 if (str == 0 || str[0] == 0) 28 return false; 29 bool start = false; 30 if (templ && templ[0] == '^') { 31 start = true; 32 templ++; 33 } 34 bool asterisk = false; 35 while (templ && templ[0]) { 36 if (templ[0] == '*') { 37 templ++; 38 start = false; 39 asterisk = true; 40 continue; 41 } 42 if (templ[0] == '$') 43 return str[0] == 0 || asterisk; 44 if (str[0] == 0) 45 return false; 46 char *tpos = (char*)internal_strchr(templ, '*'); 47 char *tpos1 = (char*)internal_strchr(templ, '$'); 48 if (tpos == 0 || (tpos1 && tpos1 < tpos)) 49 tpos = tpos1; 50 if (tpos != 0) 51 tpos[0] = 0; 52 const char *str0 = str; 53 const char *spos = internal_strstr(str, templ); 54 str = spos + internal_strlen(templ); 55 templ = tpos; 56 if (tpos) 57 tpos[0] = tpos == tpos1 ? '$' : '*'; 58 if (spos == 0) 59 return false; 60 if (start && spos != str0) 61 return false; 62 start = false; 63 asterisk = false; 64 } 65 return true; 66 } 67 68 bool SuppressionContext::Match(const char *str, SuppressionType type, 69 Suppression **s) { 70 can_parse_ = false; 71 uptr i; 72 for (i = 0; i < suppressions_.size(); i++) 73 if (type == suppressions_[i].type && 74 TemplateMatch(suppressions_[i].templ, str)) 75 break; 76 if (i == suppressions_.size()) return false; 77 *s = &suppressions_[i]; 78 return true; 79 } 80 81 static const char *StripPrefix(const char *str, const char *prefix) { 82 while (str && *str == *prefix) { 83 str++; 84 prefix++; 85 } 86 if (!*prefix) 87 return str; 88 return 0; 89 } 90 91 void SuppressionContext::Parse(const char *str) { 92 // Context must not mutate once Match has been called. 93 CHECK(can_parse_); 94 const char *line = str; 95 while (line) { 96 while (line[0] == ' ' || line[0] == '\t') 97 line++; 98 const char *end = internal_strchr(line, '\n'); 99 if (end == 0) 100 end = line + internal_strlen(line); 101 if (line != end && line[0] != '#') { 102 const char *end2 = end; 103 while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t')) 104 end2--; 105 int type; 106 for (type = 0; type < SuppressionTypeCount; type++) { 107 const char *next_char = StripPrefix(line, kTypeStrings[type]); 108 if (next_char && *next_char == ':') { 109 line = ++next_char; 110 break; 111 } 112 } 113 if (type == SuppressionTypeCount) { 114 Printf("%s: failed to parse suppressions\n", SanitizerToolName); 115 Die(); 116 } 117 Suppression s; 118 s.type = static_cast<SuppressionType>(type); 119 s.templ = (char*)InternalAlloc(end2 - line + 1); 120 internal_memcpy(s.templ, line, end2 - line); 121 s.templ[end2 - line] = 0; 122 s.hit_count = 0; 123 s.weight = 0; 124 suppressions_.push_back(s); 125 } 126 if (end[0] == 0) 127 break; 128 line = end + 1; 129 } 130 } 131 132 uptr SuppressionContext::SuppressionCount() { 133 return suppressions_.size(); 134 } 135 136 void SuppressionContext::GetMatched( 137 InternalMmapVector<Suppression *> *matched) { 138 for (uptr i = 0; i < suppressions_.size(); i++) 139 if (suppressions_[i].hit_count) 140 matched->push_back(&suppressions_[i]); 141 } 142 143 const char *SuppressionTypeString(SuppressionType t) { 144 CHECK(t < SuppressionTypeCount); 145 return kTypeStrings[t]; 146 } 147 148 } // namespace __sanitizer 149