1 //===-- SpecialCaseList.cpp - special case list for sanitizers ------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This is a utility class for instrumentation passes (like AddressSanitizer 10 // or ThreadSanitizer) to avoid instrumenting some functions or global 11 // variables, or to instrument some functions or global variables in a specific 12 // way, based on a user-supplied list. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "llvm/Support/SpecialCaseList.h" 17 #include "llvm/ADT/SmallVector.h" 18 #include "llvm/Support/MemoryBuffer.h" 19 #include "llvm/Support/Regex.h" 20 #include "llvm/Support/VirtualFileSystem.h" 21 #include <string> 22 #include <system_error> 23 #include <utility> 24 25 #include <stdio.h> 26 namespace llvm { 27 28 bool SpecialCaseList::Matcher::insert(std::string Regexp, 29 unsigned LineNumber, 30 std::string &REError) { 31 if (Regexp.empty()) { 32 REError = "Supplied regexp was blank"; 33 return false; 34 } 35 36 if (Regex::isLiteralERE(Regexp)) { 37 Strings[Regexp] = LineNumber; 38 return true; 39 } 40 41 // Replace * with .* 42 for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std::string::npos; 43 pos += strlen(".*")) { 44 Regexp.replace(pos, strlen("*"), ".*"); 45 } 46 47 Regexp = (Twine("^(") + StringRef(Regexp) + ")$").str(); 48 49 // Check that the regexp is valid. 50 Regex CheckRE(Regexp); 51 if (!CheckRE.isValid(REError)) 52 return false; 53 54 RegExes.emplace_back( 55 std::make_pair(std::make_unique<Regex>(std::move(CheckRE)), LineNumber)); 56 return true; 57 } 58 59 unsigned SpecialCaseList::Matcher::match(StringRef Query) const { 60 auto It = Strings.find(Query); 61 if (It != Strings.end()) 62 return It->second; 63 for (const auto &RegExKV : RegExes) 64 if (RegExKV.first->match(Query)) 65 return RegExKV.second; 66 return 0; 67 } 68 69 std::unique_ptr<SpecialCaseList> 70 SpecialCaseList::create(const std::vector<std::string> &Paths, 71 llvm::vfs::FileSystem &FS, std::string &Error) { 72 std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList()); 73 if (SCL->createInternal(Paths, FS, Error)) 74 return SCL; 75 return nullptr; 76 } 77 78 std::unique_ptr<SpecialCaseList> SpecialCaseList::create(const MemoryBuffer *MB, 79 std::string &Error) { 80 std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList()); 81 if (SCL->createInternal(MB, Error)) 82 return SCL; 83 return nullptr; 84 } 85 86 std::unique_ptr<SpecialCaseList> 87 SpecialCaseList::createOrDie(const std::vector<std::string> &Paths, 88 llvm::vfs::FileSystem &FS) { 89 std::string Error; 90 if (auto SCL = create(Paths, FS, Error)) 91 return SCL; 92 report_fatal_error(Twine(Error)); 93 } 94 95 bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths, 96 vfs::FileSystem &VFS, std::string &Error) { 97 StringMap<size_t> Sections; 98 for (const auto &Path : Paths) { 99 ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = 100 VFS.getBufferForFile(Path); 101 if (std::error_code EC = FileOrErr.getError()) { 102 Error = (Twine("can't open file '") + Path + "': " + EC.message()).str(); 103 return false; 104 } 105 std::string ParseError; 106 if (!parse(FileOrErr.get().get(), Sections, ParseError)) { 107 Error = (Twine("error parsing file '") + Path + "': " + ParseError).str(); 108 return false; 109 } 110 } 111 return true; 112 } 113 114 bool SpecialCaseList::createInternal(const MemoryBuffer *MB, 115 std::string &Error) { 116 StringMap<size_t> Sections; 117 if (!parse(MB, Sections, Error)) 118 return false; 119 return true; 120 } 121 122 bool SpecialCaseList::parse(const MemoryBuffer *MB, 123 StringMap<size_t> &SectionsMap, 124 std::string &Error) { 125 // Iterate through each line in the exclusion list file. 126 SmallVector<StringRef, 16> Lines; 127 MB->getBuffer().split(Lines, '\n'); 128 129 unsigned LineNo = 1; 130 StringRef Section = "*"; 131 132 for (auto I = Lines.begin(), E = Lines.end(); I != E; ++I, ++LineNo) { 133 *I = I->trim(); 134 // Ignore empty lines and lines starting with "#" 135 if (I->empty() || I->startswith("#")) 136 continue; 137 138 // Save section names 139 if (I->startswith("[")) { 140 if (!I->endswith("]")) { 141 Error = (Twine("malformed section header on line ") + Twine(LineNo) + 142 ": " + *I).str(); 143 return false; 144 } 145 146 Section = I->slice(1, I->size() - 1); 147 148 std::string REError; 149 Regex CheckRE(Section); 150 if (!CheckRE.isValid(REError)) { 151 Error = 152 (Twine("malformed regex for section ") + Section + ": '" + REError) 153 .str(); 154 return false; 155 } 156 157 continue; 158 } 159 160 // Get our prefix and unparsed regexp. 161 std::pair<StringRef, StringRef> SplitLine = I->split(":"); 162 StringRef Prefix = SplitLine.first; 163 if (SplitLine.second.empty()) { 164 // Missing ':' in the line. 165 Error = (Twine("malformed line ") + Twine(LineNo) + ": '" + 166 SplitLine.first + "'").str(); 167 return false; 168 } 169 170 std::pair<StringRef, StringRef> SplitRegexp = SplitLine.second.split("="); 171 std::string Regexp = std::string(SplitRegexp.first); 172 StringRef Category = SplitRegexp.second; 173 174 // Create this section if it has not been seen before. 175 if (!SectionsMap.contains(Section)) { 176 std::unique_ptr<Matcher> M = std::make_unique<Matcher>(); 177 std::string REError; 178 if (!M->insert(std::string(Section), LineNo, REError)) { 179 Error = (Twine("malformed section ") + Section + ": '" + REError).str(); 180 return false; 181 } 182 183 SectionsMap[Section] = Sections.size(); 184 Sections.emplace_back(std::move(M)); 185 } 186 187 auto &Entry = Sections[SectionsMap[Section]].Entries[Prefix][Category]; 188 std::string REError; 189 if (!Entry.insert(std::move(Regexp), LineNo, REError)) { 190 Error = (Twine("malformed regex in line ") + Twine(LineNo) + ": '" + 191 SplitLine.second + "': " + REError).str(); 192 return false; 193 } 194 } 195 return true; 196 } 197 198 SpecialCaseList::~SpecialCaseList() = default; 199 200 bool SpecialCaseList::inSection(StringRef Section, StringRef Prefix, 201 StringRef Query, StringRef Category) const { 202 return inSectionBlame(Section, Prefix, Query, Category); 203 } 204 205 unsigned SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix, 206 StringRef Query, 207 StringRef Category) const { 208 for (const auto &SectionIter : Sections) 209 if (SectionIter.SectionMatcher->match(Section)) { 210 unsigned Blame = 211 inSectionBlame(SectionIter.Entries, Prefix, Query, Category); 212 if (Blame) 213 return Blame; 214 } 215 return 0; 216 } 217 218 unsigned SpecialCaseList::inSectionBlame(const SectionEntries &Entries, 219 StringRef Prefix, StringRef Query, 220 StringRef Category) const { 221 SectionEntries::const_iterator I = Entries.find(Prefix); 222 if (I == Entries.end()) return 0; 223 StringMap<Matcher>::const_iterator II = I->second.find(Category); 224 if (II == I->second.end()) return 0; 225 226 return II->getValue().match(Query); 227 } 228 229 } // namespace llvm 230