LLVM  10.0.0svn
SpecialCaseList.cpp
Go to the documentation of this file.
1 //===-- SpecialCaseList.cpp - special case list for sanitizers ------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
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.
13 //
14 //===----------------------------------------------------------------------===//
15 
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/ADT/StringExtras.h"
20 #include "llvm/Support/Regex.h"
21 #include <string>
22 #include <system_error>
23 #include <utility>
24 
25 #include <stdio.h>
26 namespace llvm {
27 
28 bool SpecialCaseList::Matcher::insert(std::string Regexp,
29  unsigned LineNumber,
30  std::string &REError) {
31  if (Regexp.empty()) {
32  REError = "Supplied regexp was blank";
33  return false;
34  }
35 
36  if (Regex::isLiteralERE(Regexp)) {
37  Strings[Regexp] = LineNumber;
38  return true;
39  }
40  Trigrams.insert(Regexp);
41 
42  // Replace * with .*
43  for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std::string::npos;
44  pos += strlen(".*")) {
45  Regexp.replace(pos, strlen("*"), ".*");
46  }
47 
48  Regexp = (Twine("^(") + StringRef(Regexp) + ")$").str();
49 
50  // Check that the regexp is valid.
51  Regex CheckRE(Regexp);
52  if (!CheckRE.isValid(REError))
53  return false;
54 
55  RegExes.emplace_back(
56  std::make_pair(std::make_unique<Regex>(std::move(CheckRE)), LineNumber));
57  return true;
58 }
59 
61  auto It = Strings.find(Query);
62  if (It != Strings.end())
63  return It->second;
64  if (Trigrams.isDefinitelyOut(Query))
65  return false;
66  for (auto& RegExKV : RegExes)
67  if (RegExKV.first->match(Query))
68  return RegExKV.second;
69  return 0;
70 }
71 
72 std::unique_ptr<SpecialCaseList>
73 SpecialCaseList::create(const std::vector<std::string> &Paths,
74  std::string &Error) {
75  std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList());
76  if (SCL->createInternal(Paths, Error))
77  return SCL;
78  return nullptr;
79 }
80 
81 std::unique_ptr<SpecialCaseList> SpecialCaseList::create(const MemoryBuffer *MB,
82  std::string &Error) {
83  std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList());
84  if (SCL->createInternal(MB, Error))
85  return SCL;
86  return nullptr;
87 }
88 
89 std::unique_ptr<SpecialCaseList>
90 SpecialCaseList::createOrDie(const std::vector<std::string> &Paths) {
91  std::string Error;
92  if (auto SCL = create(Paths, Error))
93  return SCL;
94  report_fatal_error(Error);
95 }
96 
97 bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths,
98  std::string &Error) {
100  for (const auto &Path : Paths) {
102  MemoryBuffer::getFile(Path);
103  if (std::error_code EC = FileOrErr.getError()) {
104  Error = (Twine("can't open file '") + Path + "': " + EC.message()).str();
105  return false;
106  }
107  std::string ParseError;
108  if (!parse(FileOrErr.get().get(), Sections, ParseError)) {
109  Error = (Twine("error parsing file '") + Path + "': " + ParseError).str();
110  return false;
111  }
112  }
113  return true;
114 }
115 
117  std::string &Error) {
119  if (!parse(MB, Sections, Error))
120  return false;
121  return true;
122 }
123 
125  StringMap<size_t> &SectionsMap,
126  std::string &Error) {
127  // Iterate through each line in the blacklist file.
129  MB->getBuffer().split(Lines, '\n');
130 
131  unsigned LineNo = 1;
132  StringRef Section = "*";
133 
134  for (auto I = Lines.begin(), E = Lines.end(); I != E; ++I, ++LineNo) {
135  *I = I->trim();
136  // Ignore empty lines and lines starting with "#"
137  if (I->empty() || I->startswith("#"))
138  continue;
139 
140  // Save section names
141  if (I->startswith("[")) {
142  if (!I->endswith("]")) {
143  Error = (Twine("malformed section header on line ") + Twine(LineNo) +
144  ": " + *I).str();
145  return false;
146  }
147 
148  Section = I->slice(1, I->size() - 1);
149 
150  std::string REError;
151  Regex CheckRE(Section);
152  if (!CheckRE.isValid(REError)) {
153  Error =
154  (Twine("malformed regex for section ") + Section + ": '" + REError)
155  .str();
156  return false;
157  }
158 
159  continue;
160  }
161 
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();
169  return false;
170  }
171 
172  std::pair<StringRef, StringRef> SplitRegexp = SplitLine.second.split("=");
173  std::string Regexp = SplitRegexp.first;
174  StringRef Category = SplitRegexp.second;
175 
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>();
179  std::string REError;
180  if (!M->insert(Section, LineNo, REError)) {
181  Error = (Twine("malformed section ") + Section + ": '" + REError).str();
182  return false;
183  }
184 
185  SectionsMap[Section] = Sections.size();
186  Sections.emplace_back(std::move(M));
187  }
188 
189  auto &Entry = Sections[SectionsMap[Section]].Entries[Prefix][Category];
190  std::string REError;
191  if (!Entry.insert(std::move(Regexp), LineNo, REError)) {
192  Error = (Twine("malformed regex in line ") + Twine(LineNo) + ": '" +
193  SplitLine.second + "': " + REError).str();
194  return false;
195  }
196  }
197  return true;
198 }
199 
201 
203  StringRef Query, StringRef Category) const {
204  return inSectionBlame(Section, Prefix, Query, Category);
205 }
206 
208  StringRef Query,
209  StringRef Category) const {
210  for (auto &SectionIter : Sections)
211  if (SectionIter.SectionMatcher->match(Section)) {
212  unsigned Blame =
213  inSectionBlame(SectionIter.Entries, Prefix, Query, Category);
214  if (Blame)
215  return Blame;
216  }
217  return 0;
218 }
219 
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;
227 
228  return II->getValue().match(Query);
229 }
230 
231 } // namespace llvm
Represents either an error or a value T.
Definition: ErrorOr.h:56
StringRef getBuffer() const
Definition: MemoryBuffer.h:63
unsigned inSectionBlame(StringRef Section, StringRef Prefix, StringRef Query, StringRef Category=StringRef()) const
Returns the line number corresponding to the special case list entry if the special case list contain...
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:139
This class represents lattice values for constants.
Definition: AllocatorList.h:23
bool createInternal(const std::vector< std::string > &Paths, std::string &Error)
bool isDefinitelyOut(StringRef Query) const
Returns true, if special case list definitely does not have a line that matches the query...
iterator find(StringRef Key)
Definition: StringMap.h:355
bool inSection(StringRef Section, StringRef Prefix, StringRef Query, StringRef Category=StringRef()) const
Returns true, if special case list contains a line.
static std::unique_ptr< SpecialCaseList > createOrDie(const std::vector< std::string > &Paths)
Parses the special case list entries from files.
unsigned match(StringRef Query) const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:80
bool parse(const MemoryBuffer *MB, StringMap< size_t > &SectionsMap, std::string &Error)
Parses just-constructed SpecialCaseList entries from a memory buffer.
void insert(std::string Regex)
Inserts a new Regex into the index.
* if(!EatIfPresent(lltok::kw_thread_local)) return false
ParseOptionalThreadLocal := /*empty.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
std::error_code getError() const
Definition: ErrorOr.h:159
static bool isLiteralERE(StringRef Str)
If this function returns true, ^Str$ is an extended regular expression that matches Str and only Str...
Definition: Regex.cpp:208
std::vector< Section > Sections
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:837
LLVM_NODISCARD std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition: StringRef.h:710
bool isValid(std::string &Error) const
isValid - returns the error encountered during regex compilation, if any.
Definition: Regex.cpp:68
This interface provides simple read-only access to a block of memory, and provides simple methods for...
Definition: MemoryBuffer.h:41
StringMap - This is an unconventional map that is specialized for handling keys that are "strings"...
Definition: StringMap.h:242
#define I(x, y, z)
Definition: MD5.cpp:58
bool insert(std::string Regexp, unsigned LineNumber, std::string &REError)
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful, otherwise returning null.
static std::unique_ptr< SpecialCaseList > create(const std::vector< std::string > &Paths, std::string &Error)
Parses the special case list entries from files.
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
iterator end()
Definition: StringMap.h:340
reference get()
Definition: ErrorOr.h:156