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"
21 #include "llvm/Support/VirtualFileSystem.h"
23 #include <system_error>
29 bool SpecialCaseList::Matcher::insert(std::string Regexp
,
31 std::string
&REError
) {
33 REError
= "Supplied regexp was blank";
37 if (Regex::isLiteralERE(Regexp
)) {
38 Strings
[Regexp
] = LineNumber
;
41 Trigrams
.insert(Regexp
);
44 for (size_t pos
= 0; (pos
= Regexp
.find('*', pos
)) != std::string::npos
;
45 pos
+= strlen(".*")) {
46 Regexp
.replace(pos
, strlen("*"), ".*");
49 Regexp
= (Twine("^(") + StringRef(Regexp
) + ")$").str();
51 // Check that the regexp is valid.
52 Regex
CheckRE(Regexp
);
53 if (!CheckRE
.isValid(REError
))
57 std::make_pair(std::make_unique
<Regex
>(std::move(CheckRE
)), LineNumber
));
61 unsigned SpecialCaseList::Matcher::match(StringRef Query
) const {
62 auto It
= Strings
.find(Query
);
63 if (It
!= Strings
.end())
65 if (Trigrams
.isDefinitelyOut(Query
))
67 for (auto& RegExKV
: RegExes
)
68 if (RegExKV
.first
->match(Query
))
69 return RegExKV
.second
;
73 std::unique_ptr
<SpecialCaseList
>
74 SpecialCaseList::create(const std::vector
<std::string
> &Paths
,
75 llvm::vfs::FileSystem
&FS
, std::string
&Error
) {
76 std::unique_ptr
<SpecialCaseList
> SCL(new SpecialCaseList());
77 if (SCL
->createInternal(Paths
, FS
, Error
))
82 std::unique_ptr
<SpecialCaseList
> SpecialCaseList::create(const MemoryBuffer
*MB
,
84 std::unique_ptr
<SpecialCaseList
> SCL(new SpecialCaseList());
85 if (SCL
->createInternal(MB
, Error
))
90 std::unique_ptr
<SpecialCaseList
>
91 SpecialCaseList::createOrDie(const std::vector
<std::string
> &Paths
,
92 llvm::vfs::FileSystem
&FS
) {
94 if (auto SCL
= create(Paths
, FS
, Error
))
96 report_fatal_error(Error
);
99 bool SpecialCaseList::createInternal(const std::vector
<std::string
> &Paths
,
100 vfs::FileSystem
&VFS
, std::string
&Error
) {
101 StringMap
<size_t> Sections
;
102 for (const auto &Path
: Paths
) {
103 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> FileOrErr
=
104 VFS
.getBufferForFile(Path
);
105 if (std::error_code EC
= FileOrErr
.getError()) {
106 Error
= (Twine("can't open file '") + Path
+ "': " + EC
.message()).str();
109 std::string ParseError
;
110 if (!parse(FileOrErr
.get().get(), Sections
, ParseError
)) {
111 Error
= (Twine("error parsing file '") + Path
+ "': " + ParseError
).str();
118 bool SpecialCaseList::createInternal(const MemoryBuffer
*MB
,
119 std::string
&Error
) {
120 StringMap
<size_t> Sections
;
121 if (!parse(MB
, Sections
, Error
))
126 bool SpecialCaseList::parse(const MemoryBuffer
*MB
,
127 StringMap
<size_t> &SectionsMap
,
128 std::string
&Error
) {
129 // Iterate through each line in the exclusion list file.
130 SmallVector
<StringRef
, 16> Lines
;
131 MB
->getBuffer().split(Lines
, '\n');
134 StringRef Section
= "*";
136 for (auto I
= Lines
.begin(), E
= Lines
.end(); I
!= E
; ++I
, ++LineNo
) {
138 // Ignore empty lines and lines starting with "#"
139 if (I
->empty() || I
->startswith("#"))
142 // Save section names
143 if (I
->startswith("[")) {
144 if (!I
->endswith("]")) {
145 Error
= (Twine("malformed section header on line ") + Twine(LineNo
) +
150 Section
= I
->slice(1, I
->size() - 1);
153 Regex
CheckRE(Section
);
154 if (!CheckRE
.isValid(REError
)) {
156 (Twine("malformed regex for section ") + Section
+ ": '" + REError
)
164 // Get our prefix and unparsed regexp.
165 std::pair
<StringRef
, StringRef
> SplitLine
= I
->split(":");
166 StringRef Prefix
= SplitLine
.first
;
167 if (SplitLine
.second
.empty()) {
168 // Missing ':' in the line.
169 Error
= (Twine("malformed line ") + Twine(LineNo
) + ": '" +
170 SplitLine
.first
+ "'").str();
174 std::pair
<StringRef
, StringRef
> SplitRegexp
= SplitLine
.second
.split("=");
175 std::string Regexp
= std::string(SplitRegexp
.first
);
176 StringRef Category
= SplitRegexp
.second
;
178 // Create this section if it has not been seen before.
179 if (SectionsMap
.find(Section
) == SectionsMap
.end()) {
180 std::unique_ptr
<Matcher
> M
= std::make_unique
<Matcher
>();
182 if (!M
->insert(std::string(Section
), LineNo
, REError
)) {
183 Error
= (Twine("malformed section ") + Section
+ ": '" + REError
).str();
187 SectionsMap
[Section
] = Sections
.size();
188 Sections
.emplace_back(std::move(M
));
191 auto &Entry
= Sections
[SectionsMap
[Section
]].Entries
[Prefix
][Category
];
193 if (!Entry
.insert(std::move(Regexp
), LineNo
, REError
)) {
194 Error
= (Twine("malformed regex in line ") + Twine(LineNo
) + ": '" +
195 SplitLine
.second
+ "': " + REError
).str();
202 SpecialCaseList::~SpecialCaseList() {}
204 bool SpecialCaseList::inSection(StringRef Section
, StringRef Prefix
,
205 StringRef Query
, StringRef Category
) const {
206 return inSectionBlame(Section
, Prefix
, Query
, Category
);
209 unsigned SpecialCaseList::inSectionBlame(StringRef Section
, StringRef Prefix
,
211 StringRef Category
) const {
212 for (auto &SectionIter
: Sections
)
213 if (SectionIter
.SectionMatcher
->match(Section
)) {
215 inSectionBlame(SectionIter
.Entries
, Prefix
, Query
, Category
);
222 unsigned SpecialCaseList::inSectionBlame(const SectionEntries
&Entries
,
223 StringRef Prefix
, StringRef Query
,
224 StringRef Category
) const {
225 SectionEntries::const_iterator I
= Entries
.find(Prefix
);
226 if (I
== Entries
.end()) return 0;
227 StringMap
<Matcher
>::const_iterator II
= I
->second
.find(Category
);
228 if (II
== I
->second
.end()) return 0;
230 return II
->getValue().match(Query
);