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