Line data Source code
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 11893 : bool SpecialCaseList::Matcher::insert(std::string Regexp,
30 : unsigned LineNumber,
31 : std::string &REError) {
32 11893 : if (Regexp.empty()) {
33 : REError = "Supplied regexp was blank";
34 1 : return false;
35 : }
36 :
37 11892 : if (Regex::isLiteralERE(Regexp)) {
38 11127 : Strings[Regexp] = LineNumber;
39 11127 : return true;
40 : }
41 1530 : Trigrams.insert(Regexp);
42 :
43 : // Replace * with .*
44 1927 : for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std::string::npos;
45 1162 : pos += strlen(".*")) {
46 1162 : Regexp.replace(pos, strlen("*"), ".*");
47 : }
48 :
49 1530 : Regexp = (Twine("^(") + StringRef(Regexp) + ")$").str();
50 :
51 : // Check that the regexp is valid.
52 1530 : Regex CheckRE(Regexp);
53 765 : if (!CheckRE.isValid(REError))
54 : return false;
55 :
56 1526 : RegExes.emplace_back(
57 763 : std::make_pair(make_unique<Regex>(std::move(CheckRE)), LineNumber));
58 763 : return true;
59 : }
60 :
61 4357 : unsigned SpecialCaseList::Matcher::match(StringRef Query) const {
62 4357 : auto It = Strings.find(Query);
63 8714 : if (It != Strings.end())
64 72 : return It->second;
65 4285 : if (Trigrams.isDefinitelyOut(Query))
66 : return false;
67 3155 : for (auto& RegExKV : RegExes)
68 2951 : if (RegExKV.first->match(Query))
69 2680 : return RegExKV.second;
70 : return 0;
71 : }
72 :
73 : std::unique_ptr<SpecialCaseList>
74 137792 : SpecialCaseList::create(const std::vector<std::string> &Paths,
75 : std::string &Error) {
76 275584 : std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList());
77 137792 : if (SCL->createInternal(Paths, Error))
78 : return SCL;
79 : return nullptr;
80 : }
81 :
82 48 : std::unique_ptr<SpecialCaseList> SpecialCaseList::create(const MemoryBuffer *MB,
83 : std::string &Error) {
84 96 : std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList());
85 48 : if (SCL->createInternal(MB, Error))
86 : return SCL;
87 : return nullptr;
88 : }
89 :
90 : std::unique_ptr<SpecialCaseList>
91 111361 : SpecialCaseList::createOrDie(const std::vector<std::string> &Paths) {
92 : std::string Error;
93 111361 : if (auto SCL = create(Paths, Error))
94 222722 : return SCL;
95 0 : report_fatal_error(Error);
96 : }
97 :
98 174902 : bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths,
99 : std::string &Error) {
100 174902 : StringMap<size_t> Sections;
101 175214 : for (const auto &Path : Paths) {
102 : ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
103 314 : MemoryBuffer::getFile(Path);
104 314 : if (std::error_code EC = FileOrErr.getError()) {
105 3 : Error = (Twine("can't open file '") + Path + "': " + EC.message()).str();
106 : return false;
107 : }
108 : std::string ParseError;
109 313 : if (!parse(FileOrErr.get().get(), Sections, ParseError)) {
110 2 : Error = (Twine("error parsing file '") + Path + "': " + ParseError).str();
111 : return false;
112 : }
113 : }
114 : return true;
115 : }
116 :
117 48 : bool SpecialCaseList::createInternal(const MemoryBuffer *MB,
118 : std::string &Error) {
119 48 : StringMap<size_t> Sections;
120 48 : if (!parse(MB, Sections, Error))
121 8 : return false;
122 : return true;
123 : }
124 :
125 361 : 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 361 : MB->getBuffer().split(Lines, '\n');
131 :
132 : unsigned LineNo = 1;
133 : StringRef Section = "*";
134 :
135 14841 : for (auto I = Lines.begin(), E = Lines.end(); I != E; ++I, ++LineNo) {
136 14489 : *I = I->trim();
137 : // Ignore empty lines and lines starting with "#"
138 14489 : if (I->empty() || I->startswith("#"))
139 2855 : continue;
140 :
141 : // Save section names
142 : if (I->startswith("[")) {
143 : if (!I->endswith("]")) {
144 3 : Error = (Twine("malformed section header on line ") + Twine(LineNo) +
145 3 : ": " + *I).str();
146 4 : return false;
147 : }
148 :
149 58 : Section = I->slice(1, I->size() - 1);
150 :
151 : std::string REError;
152 58 : Regex CheckRE(Section);
153 58 : if (!CheckRE.isValid(REError)) {
154 : Error =
155 1 : (Twine("malformed regex for section ") + Section + ": '" + REError)
156 1 : .str();
157 1 : return false;
158 : }
159 :
160 57 : continue;
161 : }
162 :
163 : // Get our prefix and unparsed regexp.
164 11630 : std::pair<StringRef, StringRef> SplitLine = I->split(":");
165 11630 : StringRef Prefix = SplitLine.first;
166 11630 : if (SplitLine.second.empty()) {
167 : // Missing ':' in the line.
168 2 : Error = (Twine("malformed line ") + Twine(LineNo) + ": '" +
169 2 : SplitLine.first + "'").str();
170 2 : return false;
171 : }
172 :
173 11628 : std::pair<StringRef, StringRef> SplitRegexp = SplitLine.second.split("=");
174 : std::string Regexp = SplitRegexp.first;
175 11628 : StringRef Category = SplitRegexp.second;
176 :
177 : // Create this section if it has not been seen before.
178 23256 : if (SectionsMap.find(Section) == SectionsMap.end()) {
179 530 : std::unique_ptr<Matcher> M = make_unique<Matcher>();
180 : std::string REError;
181 530 : if (!M->insert(Section, LineNo, REError)) {
182 0 : Error = (Twine("malformed section ") + Section + ": '" + REError).str();
183 : return false;
184 : }
185 :
186 265 : SectionsMap[Section] = Sections.size();
187 265 : Sections.emplace_back(std::move(M));
188 : }
189 :
190 23256 : auto &Entry = Sections[SectionsMap[Section]].Entries[Prefix][Category];
191 : std::string REError;
192 23256 : if (!Entry.insert(std::move(Regexp), LineNo, REError)) {
193 3 : Error = (Twine("malformed regex in line ") + Twine(LineNo) + ": '" +
194 6 : SplitLine.second + "': " + REError).str();
195 : return false;
196 : }
197 : }
198 : return true;
199 : }
200 :
201 146730 : SpecialCaseList::~SpecialCaseList() {}
202 :
203 1287 : bool SpecialCaseList::inSection(StringRef Section, StringRef Prefix,
204 : StringRef Query, StringRef Category) const {
205 1287 : return inSectionBlame(Section, Prefix, Query, Category);
206 : }
207 :
208 1298 : unsigned SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix,
209 : StringRef Query,
210 : StringRef Category) const {
211 2301 : for (auto &SectionIter : Sections)
212 1133 : if (SectionIter.SectionMatcher->match(Section)) {
213 : unsigned Blame =
214 1109 : inSectionBlame(SectionIter.Entries, Prefix, Query, Category);
215 1109 : if (Blame)
216 : return Blame;
217 : }
218 : return 0;
219 : }
220 :
221 2339 : unsigned SpecialCaseList::inSectionBlame(const SectionEntries &Entries,
222 : StringRef Prefix, StringRef Query,
223 : StringRef Category) const {
224 2339 : SectionEntries::const_iterator I = Entries.find(Prefix);
225 4678 : if (I == Entries.end()) return 0;
226 1322 : StringMap<Matcher>::const_iterator II = I->second.find(Category);
227 2644 : if (II == I->second.end()) return 0;
228 :
229 1116 : return II->getValue().match(Query);
230 : }
231 :
232 : } // namespace llvm
|