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