1 //===-- SpecialCaseList.cpp - special case list for sanitizers ------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This is a utility class for instrumentation passes (like AddressSanitizer
10 // or ThreadSanitizer) to avoid instrumenting some functions or global
11 // variables, or to instrument some functions or global variables in a specific
12 // way, based on a user-supplied list.
14 //===----------------------------------------------------------------------===//
16 #include "llvm/Support/SpecialCaseList.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/ADT/StringExtras.h"
19 #include "llvm/Support/MemoryBuffer.h"
20 #include "llvm/Support/Regex.h"
22 #include <system_error>
28 bool SpecialCaseList::Matcher::insert(std::string Regexp
,
30 std::string
&REError
) {
32 REError
= "Supplied regexp was blank";
36 if (Regex::isLiteralERE(Regexp
)) {
37 Strings
[Regexp
] = LineNumber
;
40 Trigrams
.insert(Regexp
);
43 for (size_t pos
= 0; (pos
= Regexp
.find('*', pos
)) != std::string::npos
;
44 pos
+= strlen(".*")) {
45 Regexp
.replace(pos
, strlen("*"), ".*");
48 Regexp
= (Twine("^(") + StringRef(Regexp
) + ")$").str();
50 // Check that the regexp is valid.
51 Regex
CheckRE(Regexp
);
52 if (!CheckRE
.isValid(REError
))
56 std::make_pair(std::make_unique
<Regex
>(std::move(CheckRE
)), LineNumber
));
60 unsigned SpecialCaseList::Matcher::match(StringRef Query
) const {
61 auto It
= Strings
.find(Query
);
62 if (It
!= Strings
.end())
64 if (Trigrams
.isDefinitelyOut(Query
))
66 for (auto& RegExKV
: RegExes
)
67 if (RegExKV
.first
->match(Query
))
68 return RegExKV
.second
;
72 std::unique_ptr
<SpecialCaseList
>
73 SpecialCaseList::create(const std::vector
<std::string
> &Paths
,
75 std::unique_ptr
<SpecialCaseList
> SCL(new SpecialCaseList());
76 if (SCL
->createInternal(Paths
, Error
))
81 std::unique_ptr
<SpecialCaseList
> SpecialCaseList::create(const MemoryBuffer
*MB
,
83 std::unique_ptr
<SpecialCaseList
> SCL(new SpecialCaseList());
84 if (SCL
->createInternal(MB
, Error
))
89 std::unique_ptr
<SpecialCaseList
>
90 SpecialCaseList::createOrDie(const std::vector
<std::string
> &Paths
) {
92 if (auto SCL
= create(Paths
, Error
))
94 report_fatal_error(Error
);
97 bool SpecialCaseList::createInternal(const std::vector
<std::string
> &Paths
,
99 StringMap
<size_t> Sections
;
100 for (const auto &Path
: Paths
) {
101 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> FileOrErr
=
102 MemoryBuffer::getFile(Path
);
103 if (std::error_code EC
= FileOrErr
.getError()) {
104 Error
= (Twine("can't open file '") + Path
+ "': " + EC
.message()).str();
107 std::string ParseError
;
108 if (!parse(FileOrErr
.get().get(), Sections
, ParseError
)) {
109 Error
= (Twine("error parsing file '") + Path
+ "': " + ParseError
).str();
116 bool SpecialCaseList::createInternal(const MemoryBuffer
*MB
,
117 std::string
&Error
) {
118 StringMap
<size_t> Sections
;
119 if (!parse(MB
, Sections
, Error
))
124 bool SpecialCaseList::parse(const MemoryBuffer
*MB
,
125 StringMap
<size_t> &SectionsMap
,
126 std::string
&Error
) {
127 // Iterate through each line in the blacklist file.
128 SmallVector
<StringRef
, 16> Lines
;
129 MB
->getBuffer().split(Lines
, '\n');
132 StringRef Section
= "*";
134 for (auto I
= Lines
.begin(), E
= Lines
.end(); I
!= E
; ++I
, ++LineNo
) {
136 // Ignore empty lines and lines starting with "#"
137 if (I
->empty() || I
->startswith("#"))
140 // Save section names
141 if (I
->startswith("[")) {
142 if (!I
->endswith("]")) {
143 Error
= (Twine("malformed section header on line ") + Twine(LineNo
) +
148 Section
= I
->slice(1, I
->size() - 1);
151 Regex
CheckRE(Section
);
152 if (!CheckRE
.isValid(REError
)) {
154 (Twine("malformed regex for section ") + Section
+ ": '" + REError
)
162 // Get our prefix and unparsed regexp.
163 std::pair
<StringRef
, StringRef
> SplitLine
= I
->split(":");
164 StringRef Prefix
= SplitLine
.first
;
165 if (SplitLine
.second
.empty()) {
166 // Missing ':' in the line.
167 Error
= (Twine("malformed line ") + Twine(LineNo
) + ": '" +
168 SplitLine
.first
+ "'").str();
172 std::pair
<StringRef
, StringRef
> SplitRegexp
= SplitLine
.second
.split("=");
173 std::string Regexp
= SplitRegexp
.first
;
174 StringRef Category
= SplitRegexp
.second
;
176 // Create this section if it has not been seen before.
177 if (SectionsMap
.find(Section
) == SectionsMap
.end()) {
178 std::unique_ptr
<Matcher
> M
= std::make_unique
<Matcher
>();
180 if (!M
->insert(Section
, LineNo
, REError
)) {
181 Error
= (Twine("malformed section ") + Section
+ ": '" + REError
).str();
185 SectionsMap
[Section
] = Sections
.size();
186 Sections
.emplace_back(std::move(M
));
189 auto &Entry
= Sections
[SectionsMap
[Section
]].Entries
[Prefix
][Category
];
191 if (!Entry
.insert(std::move(Regexp
), LineNo
, REError
)) {
192 Error
= (Twine("malformed regex in line ") + Twine(LineNo
) + ": '" +
193 SplitLine
.second
+ "': " + REError
).str();
200 SpecialCaseList::~SpecialCaseList() {}
202 bool SpecialCaseList::inSection(StringRef Section
, StringRef Prefix
,
203 StringRef Query
, StringRef Category
) const {
204 return inSectionBlame(Section
, Prefix
, Query
, Category
);
207 unsigned SpecialCaseList::inSectionBlame(StringRef Section
, StringRef Prefix
,
209 StringRef Category
) const {
210 for (auto &SectionIter
: Sections
)
211 if (SectionIter
.SectionMatcher
->match(Section
)) {
213 inSectionBlame(SectionIter
.Entries
, Prefix
, Query
, Category
);
220 unsigned SpecialCaseList::inSectionBlame(const SectionEntries
&Entries
,
221 StringRef Prefix
, StringRef Query
,
222 StringRef Category
) const {
223 SectionEntries::const_iterator I
= Entries
.find(Prefix
);
224 if (I
== Entries
.end()) return 0;
225 StringMap
<Matcher
>::const_iterator II
= I
->second
.find(Category
);
226 if (II
== I
->second
.end()) return 0;
228 return II
->getValue().match(Query
);