llvm.org GIT mirror llvm / 1e4d340
Add section headers to SpecialCaseLists Summary: Sanitizer blacklist entries currently apply to all sanitizers--there is no way to specify that an entry should only apply to a specific sanitizer. This is important for Control Flow Integrity since there are several different CFI modes that can be enabled at once. For maximum security, CFI blacklist entries should be scoped to only the specific CFI mode(s) that entry applies to. Adding section headers to SpecialCaseLists allows users to specify more information about list entries, like sanitizer names or other metadata, like so: [section1] fun:*fun1* [section2|section3] fun:*fun23* The section headers are regular expressions. For backwards compatbility, blacklist entries entered before a section header are put into the '[*]' section so that blacklists without sections retain the same behavior. SpecialCaseList has been modified to also accept a section name when matching against the blacklist. It has also been modified so the follow-up change to clang can define a derived class that allows matching sections by SectionMask instead of by string. Reviewers: pcc, kcc, eugenis, vsk Reviewed By: eugenis, vsk Subscribers: vitalybuka, llvm-commits Differential Revision: https://reviews.llvm.org/D37924 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@314170 91177308-0d34-0410-b5e6-96231b3b80d8 Vlad Tsyrklevich 1 year, 11 months ago
6 changed file(s) with 304 addition(s) and 164 deletion(s). Raw diff Collapse all Expand all
77 //
88 // This is a utility class used to parse user-provided text files with
99 // "special case lists" for code sanitizers. Such files are used to
10 // define "ABI list" for DataFlowSanitizer and blacklists for another sanitizers
10 // define an "ABI list" for DataFlowSanitizer and blacklists for sanitizers
1111 // like AddressSanitizer or UndefinedBehaviorSanitizer.
1212 //
13 // Empty lines and lines starting with "#" are ignored. All the rest lines
14 // should have the form:
15 // section:wildcard_expression[=category]
13 // Empty lines and lines starting with "#" are ignored. Sections are defined
14 // using a '[section_name]' header and can be used to specify sanitizers the
15 // entries below it apply to. Section names are regular expressions, and
16 // entries without a section header match all sections (e.g. an '[*]' header
17 // is assumed.)
18 // The remaining lines should have the form:
19 // prefix:wildcard_expression[=category]
1620 // If category is not specified, it is assumed to be empty string.
17 // Definitions of "section" and "category" are sanitizer-specific. For example,
18 // sanitizer blacklists support sections "src", "fun" and "global".
21 // Definitions of "prefix" and "category" are sanitizer-specific. For example,
22 // sanitizer blacklists support prefixes "src", "fun" and "global".
1923 // Wildcard expressions define, respectively, source files, functions or
2024 // globals which shouldn't be instrumented.
2125 // Examples of categories:
2529 // detection for certain globals or source files.
2630 // Full special case list file example:
2731 // ---
32 // [address]
2833 // # Blacklisted items:
2934 // fun:*_ZN4base6subtle*
3035 // global:*global_with_bad_access_or_initialization*
3338 // src:file_with_tricky_code.cc
3439 // src:ignore-global-initializers-issues.cc=init
3540 //
41 // [dataflow]
3642 // # Functions with pure functional semantics:
3743 // fun:cos=functional
3844 // fun:sin=functional
3945 // ---
4046 // Note that the wild card is in fact an llvm::Regex, but * is automatically
4147 // replaced with .*
42 // This is similar to the "ignore" feature of ThreadSanitizer.
43 // http://code.google.com/p/data-race-test/wiki/ThreadSanitizerIgnores
4448 //
4549 //===----------------------------------------------------------------------===//
4650
4852 #define LLVM_SUPPORT_SPECIALCASELIST_H
4953
5054 #include "llvm/ADT/StringMap.h"
55 #include "llvm/ADT/StringSet.h"
56 #include "llvm/Support/Regex.h"
57 #include "llvm/Support/TrigramIndex.h"
5158 #include
5259 #include
5360
7582
7683 /// Returns true, if special case list contains a line
7784 /// \code
78 /// @Section:=@Category
85 /// @Prefix:=@Category
7986 /// \endcode
80 /// and @Query satisfies a wildcard expression .
81 bool inSection(StringRef Section, StringRef Query,
87 /// where @Query satisfies wildcard expression in a given @Section.
88 bool inSection(StringRef Section, StringRef Prefix, StringRef Query,
8289 StringRef Category = StringRef()) const;
8390
84 private:
91 protected:
92 // Implementations of the create*() functions that can also be used by derived
93 // classes.
94 bool createInternal(const std::vector &Paths,
95 std::string &Error);
96 bool createInternal(const MemoryBuffer *MB, std::string &Error);
97
8598 SpecialCaseList(SpecialCaseList const &) = delete;
8699 SpecialCaseList &operator=(SpecialCaseList const &) = delete;
87100
88 struct Entry;
89 StringMap> Entries;
90 StringMap> Regexps;
101 /// Represents a set of regular expressions. Regular expressions which are
102 /// "literal" (i.e. no regex metacharacters) are stored in Strings, while all
103 /// others are represented as a single pipe-separated regex in RegEx. The
104 /// reason for doing so is efficiency; StringSet is much faster at matching
105 /// literal strings than Regex.
106 class Matcher {
107 public:
108 bool insert(std::string Regexp, std::string &REError);
109 void compile();
110 bool match(StringRef Query) const;
111
112 private:
113 StringSet<> Strings;
114 TrigramIndex Trigrams;
115 std::unique_ptr RegEx;
116 std::string UncompiledRegEx;
117 };
118
119 using SectionEntries = StringMap>;
120
121 struct Section {
122 Section(std::unique_ptr M) : SectionMatcher(std::move(M)){};
123
124 std::unique_ptr SectionMatcher;
125 SectionEntries Entries;
126 };
127
128 std::vector
Sections;
91129 bool IsCompiled;
92130
93131 SpecialCaseList();
94132 /// Parses just-constructed SpecialCaseList entries from a memory buffer.
95 bool parse(const MemoryBuffer *MB, std::string &Error);
133 bool parse(const MemoryBuffer *MB, StringMap &SectionsMap,
134 std::string &Error);
96135 /// compile() should be called once, after parsing all the memory buffers.
97136 void compile();
137
138 // Helper method for derived classes to search by Prefix, Query, and Category
139 // once they have already resolved a section entry.
140 bool inSection(const SectionEntries &Entries, StringRef Prefix,
141 StringRef Query, StringRef Category) const;
98142 };
99143
100144 } // namespace llvm
1616 #include "llvm/Support/SpecialCaseList.h"
1717 #include "llvm/ADT/SmallVector.h"
1818 #include "llvm/ADT/StringExtras.h"
19 #include "llvm/ADT/StringSet.h"
2019 #include "llvm/Support/MemoryBuffer.h"
2120 #include "llvm/Support/Regex.h"
22 #include "llvm/Support/TrigramIndex.h"
2321 #include
2422 #include
2523 #include
2624
25 #include
2726 namespace llvm {
2827
29 /// Represents a set of regular expressions. Regular expressions which are
30 /// "literal" (i.e. no regex metacharacters) are stored in Strings, while all
31 /// others are represented as a single pipe-separated regex in RegEx. The
32 /// reason for doing so is efficiency; StringSet is much faster at matching
33 /// literal strings than Regex.
34 struct SpecialCaseList::Entry {
35 StringSet<> Strings;
36 TrigramIndex Trigrams;
37 std::unique_ptr RegEx;
38
39 bool match(StringRef Query) const {
40 if (Strings.count(Query))
41 return true;
42 if (Trigrams.isDefinitelyOut(Query))
43 return false;
44 return RegEx && RegEx->match(Query);
45 }
46 };
47
48 SpecialCaseList::SpecialCaseList() : Entries(), Regexps(), IsCompiled(false) {}
28 bool SpecialCaseList::Matcher::insert(std::string Regexp,
29 std::string &REError) {
30 if (Regex::isLiteralERE(Regexp)) {
31 Strings.insert(Regexp);
32 return true;
33 }
34 Trigrams.insert(Regexp);
35
36 // Replace * with .*
37 for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std::string::npos;
38 pos += strlen(".*")) {
39 Regexp.replace(pos, strlen("*"), ".*");
40 }
41
42 // Check that the regexp is valid.
43 Regex CheckRE(Regexp);
44 if (!CheckRE.isValid(REError))
45 return false;
46
47 if (!UncompiledRegEx.empty())
48 UncompiledRegEx += "|";
49 UncompiledRegEx += "^(" + Regexp + ")$";
50 return true;
51 }
52
53 void SpecialCaseList::Matcher::compile() {
54 if (!UncompiledRegEx.empty()) {
55 RegEx.reset(new Regex(UncompiledRegEx));
56 UncompiledRegEx.clear();
57 }
58 }
59
60 bool SpecialCaseList::Matcher::match(StringRef Query) const {
61 if (Strings.count(Query))
62 return true;
63 if (Trigrams.isDefinitelyOut(Query))
64 return false;
65 return RegEx && RegEx->match(Query);
66 }
67
68 SpecialCaseList::SpecialCaseList() : Sections(), IsCompiled(false) {}
4969
5070 std::unique_ptr
5171 SpecialCaseList::create(const std::vector &Paths,
5272 std::string &Error) {
5373 std::unique_ptr SCL(new SpecialCaseList());
54 for (const auto &Path : Paths) {
55 ErrorOr> FileOrErr =
56 MemoryBuffer::getFile(Path);
57 if (std::error_code EC = FileOrErr.getError()) {
58 Error = (Twine("can't open file '") + Path + "': " + EC.message()).str();
59 return nullptr;
60 }
61 std::string ParseError;
62 if (!SCL->parse(FileOrErr.get().get(), ParseError)) {
63 Error = (Twine("error parsing file '") + Path + "': " + ParseError).str();
64 return nullptr;
65 }
66 }
67 SCL->compile();
68 return SCL;
74 if (SCL->createInternal(Paths, Error))
75 return SCL;
76 return nullptr;
6977 }
7078
7179 std::unique_ptr SpecialCaseList::create(const MemoryBuffer *MB,
7280 std::string &Error) {
7381 std::unique_ptr SCL(new SpecialCaseList());
74 if (!SCL->parse(MB, Error))
75 return nullptr;
76 SCL->compile();
77 return SCL;
82 if (SCL->createInternal(MB, Error))
83 return SCL;
84 return nullptr;
7885 }
7986
8087 std::unique_ptr
8592 report_fatal_error(Error);
8693 }
8794
88 bool SpecialCaseList::parse(const MemoryBuffer *MB, std::string &Error) {
95 bool SpecialCaseList::createInternal(const std::vector &Paths,
96 std::string &Error) {
97 StringMap Sections;
98 for (const auto &Path : Paths) {
99 ErrorOr> FileOrErr =
100 MemoryBuffer::getFile(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 compile();
112 return true;
113 }
114
115 bool SpecialCaseList::createInternal(const MemoryBuffer *MB,
116 std::string &Error) {
117 StringMap Sections;
118 if (!parse(MB, Sections, Error))
119 return false;
120 compile();
121 return true;
122 }
123
124 bool SpecialCaseList::parse(const MemoryBuffer *MB,
125 StringMap &SectionsMap,
126 std::string &Error) {
89127 // Iterate through each line in the blacklist file.
90128 SmallVector Lines;
91129 SplitString(MB->getBuffer(), Lines, "\n\r");
130
92131 int LineNo = 1;
132 StringRef Section = "*";
93133 for (auto I = Lines.begin(), E = Lines.end(); I != E; ++I, ++LineNo) {
94134 // Ignore empty lines and lines starting with "#"
95135 if (I->empty() || I->startswith("#"))
96136 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
97160 // Get our prefix and unparsed regexp.
98161 std::pair SplitLine = I->split(":");
99162 StringRef Prefix = SplitLine.first;
108171 std::string Regexp = SplitRegexp.first;
109172 StringRef Category = SplitRegexp.second;
110173
111 // See if we can store Regexp in Strings.
112 auto &Entry = Entries[Prefix][Category];
113 if (Regex::isLiteralERE(Regexp)) {
114 Entry.Strings.insert(Regexp);
115 continue;
116 }
117 Entry.Trigrams.insert(Regexp);
118
119 // Replace * with .*
120 for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std::string::npos;
121 pos += strlen(".*")) {
122 Regexp.replace(pos, strlen("*"), ".*");
123 }
124
125 // Check that the regexp is valid.
126 Regex CheckRE(Regexp);
174 // Create this section if it has not been seen before.
175 if (SectionsMap.find(Section) == SectionsMap.end()) {
176 std::unique_ptr M = make_unique();
177 std::string REError;
178 if (!M->insert(Section, REError)) {
179 Error = (Twine("malformed section ") + Section + ": '" + REError).str();
180 return false;
181 }
182 M->compile();
183
184 SectionsMap[Section] = Sections.size();
185 Sections.emplace_back(std::move(M));
186 }
187
188 auto &Entry = Sections[SectionsMap[Section]].Entries[Prefix][Category];
127189 std::string REError;
128 if (!CheckRE.isValid(REError)) {
190 if (!Entry.insert(std::move(Regexp), REError)) {
129191 Error = (Twine("malformed regex in line ") + Twine(LineNo) + ": '" +
130192 SplitLine.second + "': " + REError).str();
131193 return false;
132194 }
133
134 // Add this regexp into the proper group by its prefix.
135 if (!Regexps[Prefix][Category].empty())
136 Regexps[Prefix][Category] += "|";
137 Regexps[Prefix][Category] += "^" + Regexp + "$";
138195 }
139196 return true;
140197 }
141198
142199 void SpecialCaseList::compile() {
143200 assert(!IsCompiled && "compile() should only be called once");
144 // Iterate through each of the prefixes, and create Regexs for them.
145 for (StringMap>::const_iterator I = Regexps.begin(),
146 E = Regexps.end();
147 I != E; ++I) {
148 for (StringMap::const_iterator II = I->second.begin(),
149 IE = I->second.end();
150 II != IE; ++II) {
151 Entries[I->getKey()][II->getKey()].RegEx.reset(new Regex(II->getValue()));
152 }
153 }
154 Regexps.clear();
201 // Iterate through every section compiling regular expressions for every query
202 // and creating Section entries.
203 for (auto &Section : Sections)
204 for (auto &Prefix : Section.Entries)
205 for (auto &Category : Prefix.getValue())
206 Category.getValue().compile();
207
155208 IsCompiled = true;
156209 }
157210
158211 SpecialCaseList::~SpecialCaseList() {}
159212
160 bool SpecialCaseList::inSection(StringRef Section, StringRef Query,
161 StringRef Category) const {
213 bool SpecialCaseList::inSection(StringRef Section, StringRef Prefix,
214 StringRef Query, StringRef Category) const {
162215 assert(IsCompiled && "SpecialCaseList::compile() was not called!");
163 StringMap >::const_iterator I = Entries.find(Section);
216
217 for (auto &SectionIter : Sections)
218 if (SectionIter.SectionMatcher->match(Section) &&
219 inSection(SectionIter.Entries, Prefix, Query, Category))
220 return true;
221
222 return false;
223 }
224
225 bool SpecialCaseList::inSection(const SectionEntries &Entries, StringRef Prefix,
226 StringRef Query, StringRef Category) const {
227 SectionEntries::const_iterator I = Entries.find(Prefix);
164228 if (I == Entries.end()) return false;
165 StringMap<Entry>::const_iterator II = I->second.find(Category);
229 StringMap<Matcher>::const_iterator II = I->second.find(Category);
166230 if (II == I->second.end()) return false;
167231
168232 return II->getValue().match(Query);
154154 /// given category.
155155 bool isIn(const Function &F, StringRef Category) const {
156156 return isIn(*F.getParent(), Category) ||
157 SCL->inSection("fun", F.getName(), Category);
157 SCL->inSection("dataflow", "fun", F.getName(), Category);
158158 }
159159
160160 /// Returns whether this global alias is listed in the given category.
166166 return true;
167167
168168 if (isa(GA.getValueType()))
169 return SCL->inSection("fun", GA.getName(), Category);
170
171 return SCL->inSection("global", GA.getName(), Category) ||
172 SCL->inSection("type", GetGlobalTypeString(GA), Category);
169 return SCL->inSection("dataflow", "fun", GA.getName(), Category);
170
171 return SCL->inSection("dataflow", "global", GA.getName(), Category) ||
172 SCL->inSection("dataflow", "type", GetGlobalTypeString(GA),
173 Category);
173174 }
174175
175176 /// Returns whether this module is listed in the given category.
176177 bool isIn(const Module &M, StringRef Category) const {
177 return SCL->inSection("src", M.getModuleIdentifier(), Category);
178 return SCL->inSection("dataflow", "src", M.getModuleIdentifier(), Category);
178179 }
179180 };
180181
3131 bool NameWhitelistCoverageFilter::matches(
3232 const coverage::CoverageMapping &,
3333 const coverage::FunctionRecord &Function) {
34 return Whitelist.inSection("whitelist_fun", Function.Name);
34 return Whitelist.inSection("llvmcov", "whitelist_fun", Function.Name);
3535 }
3636
3737 bool RegionCoverageFilter::matches(const coverage::CoverageMapping &CM,
583583 UserBlacklist(createUserBlacklist()) {}
584584
585585 bool isBlacklisted(const DILineInfo &I) {
586 if (DefaultBlacklist && DefaultBlacklist->inSection("fun", I.FunctionName))
586 if (DefaultBlacklist &&
587 DefaultBlacklist->inSection("sancov", "fun", I.FunctionName))
587588 return true;
588 if (DefaultBlacklist && DefaultBlacklist->inSection("src", I.FileName))
589 if (DefaultBlacklist &&
590 DefaultBlacklist->inSection("sancov", "src", I.FileName))
589591 return true;
590 if (UserBlacklist && UserBlacklist->inSection("fun", I.FunctionName))
592 if (UserBlacklist &&
593 UserBlacklist->inSection("sancov", "fun", I.FunctionName))
591594 return true;
592 if (UserBlacklist && UserBlacklist->inSection("src", I.FileName))
595 if (UserBlacklist && UserBlacklist->inSection("sancov", "src", I.FileName))
593596 return true;
594597 return false;
595598 }
5050 "src:bye\n"
5151 "src:hi=category\n"
5252 "src:z*=category\n");
53 EXPECT_TRUE(SCL->inSection("src", "hello"));
54 EXPECT_TRUE(SCL->inSection("src", "bye"));
55 EXPECT_TRUE(SCL->inSection("src", "hi", "category"));
56 EXPECT_TRUE(SCL->inSection("src", "zzzz", "category"));
57 EXPECT_FALSE(SCL->inSection("src", "hi"));
58 EXPECT_FALSE(SCL->inSection("fun", "hello"));
59 EXPECT_FALSE(SCL->inSection("src", "hello", "category"));
53 EXPECT_TRUE(SCL->inSection("", "src", "hello"));
54 EXPECT_TRUE(SCL->inSection("", "src", "bye"));
55 EXPECT_TRUE(SCL->inSection("", "src", "hi", "category"));
56 EXPECT_TRUE(SCL->inSection("", "src", "zzzz", "category"));
57 EXPECT_FALSE(SCL->inSection("", "src", "hi"));
58 EXPECT_FALSE(SCL->inSection("", "fun", "hello"));
59 EXPECT_FALSE(SCL->inSection("", "src", "hello", "category"));
60 }
61
62 TEST_F(SpecialCaseListTest, SectionRegexErrorHandling) {
63 std::string Error;
64 EXPECT_EQ(makeSpecialCaseList("[address", Error), nullptr);
65 EXPECT_TRUE(((StringRef)Error).startswith("malformed section header "));
66
67 EXPECT_EQ(makeSpecialCaseList("[[]", Error), nullptr);
68 EXPECT_TRUE(((StringRef)Error).startswith("malformed regex for section [: "));
69 }
70
71 TEST_F(SpecialCaseListTest, Section) {
72 std::unique_ptr SCL = makeSpecialCaseList("src:global\n"
73 "[sect1|sect2]\n"
74 "src:test1\n"
75 "[sect3*]\n"
76 "src:test2\n");
77 EXPECT_TRUE(SCL->inSection("arbitrary", "src", "global"));
78 EXPECT_TRUE(SCL->inSection("", "src", "global"));
79 EXPECT_TRUE(SCL->inSection("sect1", "src", "test1"));
80 EXPECT_FALSE(SCL->inSection("sect1-arbitrary", "src", "test1"));
81 EXPECT_FALSE(SCL->inSection("sect", "src", "test1"));
82 EXPECT_FALSE(SCL->inSection("sect1", "src", "test2"));
83 EXPECT_TRUE(SCL->inSection("sect2", "src", "test1"));
84 EXPECT_TRUE(SCL->inSection("sect3", "src", "test2"));
85 EXPECT_TRUE(SCL->inSection("sect3-arbitrary", "src", "test2"));
86 EXPECT_FALSE(SCL->inSection("", "src", "test1"));
87 EXPECT_FALSE(SCL->inSection("", "src", "test2"));
6088 }
6189
6290 TEST_F(SpecialCaseListTest, GlobalInit) {
6391 std::unique_ptr SCL =
6492 makeSpecialCaseList("global:foo=init\n");
65 EXPECT_FALSE(SCL->inSection("global", "foo"));
66 EXPECT_FALSE(SCL->inSection("global", "bar"));
67 EXPECT_TRUE(SCL->inSection("global", "foo", "init"));
68 EXPECT_FALSE(SCL->inSection("global", "bar", "init"));
93 EXPECT_FALSE(SCL->inSection("", "global", "foo"));
94 EXPECT_FALSE(SCL->inSection("", "global", "bar"));
95 EXPECT_TRUE(SCL->inSection("", "global", "foo", "init"));
96 EXPECT_FALSE(SCL->inSection("", "global", "bar", "init"));
6997
7098 SCL = makeSpecialCaseList("type:t2=init\n");
71 EXPECT_FALSE(SCL->inSection("type", "t1"));
72 EXPECT_FALSE(SCL->inSection("type", "t2"));
73 EXPECT_FALSE(SCL->inSection("type", "t1", "init"));
74 EXPECT_TRUE(SCL->inSection("type", "t2", "init"));
99 EXPECT_FALSE(SCL->inSection("", "type", "t1"));
100 EXPECT_FALSE(SCL->inSection("", "type", "t2"));
101 EXPECT_FALSE(SCL->inSection("", "type", "t1", "init"));
102 EXPECT_TRUE(SCL->inSection("", "type", "t2", "init"));
75103
76104 SCL = makeSpecialCaseList("src:hello=init\n");
77 EXPECT_FALSE(SCL->inSection("src", "hello"));
78 EXPECT_FALSE(SCL->inSection("src", "bye"));
79 EXPECT_TRUE(SCL->inSection("src", "hello", "init"));
80 EXPECT_FALSE(SCL->inSection("src", "bye", "init"));
105 EXPECT_FALSE(SCL->inSection("", "src", "hello"));
106 EXPECT_FALSE(SCL->inSection("", "src", "bye"));
107 EXPECT_TRUE(SCL->inSection("", "src", "hello", "init"));
108 EXPECT_FALSE(SCL->inSection("", "src", "bye", "init"));
81109 }
82110
83111 TEST_F(SpecialCaseListTest, Substring) {
84112 std::unique_ptr SCL = makeSpecialCaseList("src:hello\n"
85113 "fun:foo\n"
86114 "global:bar\n");
87 EXPECT_FALSE(SCL->inSection("src", "othello"));
88 EXPECT_FALSE(SCL->inSection("fun", "tomfoolery"));
89 EXPECT_FALSE(SCL->inSection("global", "bartender"));
115 EXPECT_FALSE(SCL->inSection("", "src", "othello"));
116 EXPECT_FALSE(SCL->inSection("", "fun", "tomfoolery"));
117 EXPECT_FALSE(SCL->inSection("", "global", "bartender"));
90118
91119 SCL = makeSpecialCaseList("fun:*foo*\n");
92 EXPECT_TRUE(SCL->inSection("fun", "tomfoolery"));
93 EXPECT_TRUE(SCL->inSection("fun", "foobar"));
120 EXPECT_TRUE(SCL->inSection("", "fun", "tomfoolery"));
121 EXPECT_TRUE(SCL->inSection("", "fun", "foobar"));
94122 }
95123
96124 TEST_F(SpecialCaseListTest, InvalidSpecialCaseList) {
112140
113141 TEST_F(SpecialCaseListTest, EmptySpecialCaseList) {
114142 std::unique_ptr SCL = makeSpecialCaseList("");
115 EXPECT_FALSE(SCL->inSection("foo", "bar"));
143 EXPECT_FALSE(SCL->inSection("", "foo", "bar"));
116144 }
117145
118146 TEST_F(SpecialCaseListTest, MultipleBlacklists) {
123151 Files.push_back(makeSpecialCaseListFile("src:baz\n"
124152 "src:*fog*\n"));
125153 auto SCL = SpecialCaseList::createOrDie(Files);
126 EXPECT_TRUE(SCL->inSection("src", "bar"));
127 EXPECT_TRUE(SCL->inSection("src", "baz"));
128 EXPECT_FALSE(SCL->inSection("src", "ban"));
129 EXPECT_TRUE(SCL->inSection("src", "ban", "init"));
130 EXPECT_TRUE(SCL->inSection("src", "tomfoolery"));
131 EXPECT_TRUE(SCL->inSection("src", "tomfoglery"));
154 EXPECT_TRUE(SCL->inSection("", "src", "bar"));
155 EXPECT_TRUE(SCL->inSection("", "src", "baz"));
156 EXPECT_FALSE(SCL->inSection("", "src", "ban"));
157 EXPECT_TRUE(SCL->inSection("", "src", "ban", "init"));
158 EXPECT_TRUE(SCL->inSection("", "src", "tomfoolery"));
159 EXPECT_TRUE(SCL->inSection("", "src", "tomfoglery"));
132160 for (auto &Path : Files)
133161 sys::fs::remove(Path);
134162 }
136164 TEST_F(SpecialCaseListTest, NoTrigramsInRules) {
137165 std::unique_ptr SCL = makeSpecialCaseList("fun:b.r\n"
138166 "fun:za*az\n");
139 EXPECT_TRUE(SCL->inSection("fun", "bar"));
140 EXPECT_FALSE(SCL->inSection("fun", "baz"));
141 EXPECT_TRUE(SCL->inSection("fun", "zakaz"));
142 EXPECT_FALSE(SCL->inSection("fun", "zaraza"));
167 EXPECT_TRUE(SCL->inSection("", "fun", "bar"));
168 EXPECT_FALSE(SCL->inSection("", "fun", "baz"));
169 EXPECT_TRUE(SCL->inSection("", "fun", "zakaz"));
170 EXPECT_FALSE(SCL->inSection("", "fun", "zaraza"));
143171 }
144172
145173 TEST_F(SpecialCaseListTest, NoTrigramsInARule) {
146174 std::unique_ptr SCL = makeSpecialCaseList("fun:*bar*\n"
147175 "fun:za*az\n");
148 EXPECT_TRUE(SCL->inSection("fun", "abara"));
149 EXPECT_FALSE(SCL->inSection("fun", "bor"));
150 EXPECT_TRUE(SCL->inSection("fun", "zakaz"));
151 EXPECT_FALSE(SCL->inSection("fun", "zaraza"));
176 EXPECT_TRUE(SCL->inSection("", "fun", "abara"));
177 EXPECT_FALSE(SCL->inSection("", "fun", "bor"));
178 EXPECT_TRUE(SCL->inSection("", "fun", "zakaz"));
179 EXPECT_FALSE(SCL->inSection("", "fun", "zaraza"));
152180 }
153181
154182 TEST_F(SpecialCaseListTest, RepetitiveRule) {
155183 std::unique_ptr SCL = makeSpecialCaseList("fun:*bar*bar*bar*bar*\n"
156184 "fun:bar*\n");
157 EXPECT_TRUE(SCL->inSection("fun", "bara"));
158 EXPECT_FALSE(SCL->inSection("fun", "abara"));
159 EXPECT_TRUE(SCL->inSection("fun", "barbarbarbar"));
160 EXPECT_TRUE(SCL->inSection("fun", "abarbarbarbar"));
161 EXPECT_FALSE(SCL->inSection("fun", "abarbarbar"));
185 EXPECT_TRUE(SCL->inSection("", "fun", "bara"));
186 EXPECT_FALSE(SCL->inSection("", "fun", "abara"));
187 EXPECT_TRUE(SCL->inSection("", "fun", "barbarbarbar"));
188 EXPECT_TRUE(SCL->inSection("", "fun", "abarbarbarbar"));
189 EXPECT_FALSE(SCL->inSection("", "fun", "abarbarbar"));
162190 }
163191
164192 TEST_F(SpecialCaseListTest, SpecialSymbolRule) {
165193 std::unique_ptr SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n");
166 EXPECT_TRUE(SCL->inSection("src", "c++abi"));
167 EXPECT_FALSE(SCL->inSection("src", "c\\+\\+abi"));
194 EXPECT_TRUE(SCL->inSection("", "src", "c++abi"));
195 EXPECT_FALSE(SCL->inSection("", "src", "c\\+\\+abi"));
168196 }
169197
170198 TEST_F(SpecialCaseListTest, PopularTrigram) {
172200 "fun:*aaaaa*\n"
173201 "fun:*aaaa*\n"
174202 "fun:*aaa*\n");
175 EXPECT_TRUE(SCL->inSection("fun", "aaa"));
176 EXPECT_TRUE(SCL->inSection("fun", "aaaa"));
177 EXPECT_TRUE(SCL->inSection("fun", "aaaabbbaaa"));
203 EXPECT_TRUE(SCL->inSection("", "fun", "aaa"));
204 EXPECT_TRUE(SCL->inSection("", "fun", "aaaa"));
205 EXPECT_TRUE(SCL->inSection("", "fun", "aaaabbbaaa"));
178206 }
179207
180208 TEST_F(SpecialCaseListTest, EscapedSymbols) {
181209 std::unique_ptr SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n"
182210 "src:*hello\\\\world*\n");
183 EXPECT_TRUE(SCL->inSection("src", "dir/c++abi"));
184 EXPECT_FALSE(SCL->inSection("src", "dir/c\\+\\+abi"));
185 EXPECT_FALSE(SCL->inSection("src", "c\\+\\+abi"));
186 EXPECT_TRUE(SCL->inSection("src", "C:\\hello\\world"));
187 EXPECT_TRUE(SCL->inSection("src", "hello\\world"));
188 EXPECT_FALSE(SCL->inSection("src", "hello\\\\world"));
189 }
190
191 }
211 EXPECT_TRUE(SCL->inSection("", "src", "dir/c++abi"));
212 EXPECT_FALSE(SCL->inSection("", "src", "dir/c\\+\\+abi"));
213 EXPECT_FALSE(SCL->inSection("", "src", "c\\+\\+abi"));
214 EXPECT_TRUE(SCL->inSection("", "src", "C:\\hello\\world"));
215 EXPECT_TRUE(SCL->inSection("", "src", "hello\\world"));
216 EXPECT_FALSE(SCL->inSection("", "src", "hello\\\\world"));
217 }
218
219 }