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