mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
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 llvm-svn: 314170
This commit is contained in:
parent
4fd32329a6
commit
0b4abdf3cc
@ -8,15 +8,19 @@
|
|||||||
//
|
//
|
||||||
// This is a utility class used to parse user-provided text files with
|
// This is a utility class used to parse user-provided text files with
|
||||||
// "special case lists" for code sanitizers. Such files are used to
|
// "special case lists" for code sanitizers. Such files are used to
|
||||||
// define "ABI list" for DataFlowSanitizer and blacklists for another sanitizers
|
// define an "ABI list" for DataFlowSanitizer and blacklists for sanitizers
|
||||||
// like AddressSanitizer or UndefinedBehaviorSanitizer.
|
// like AddressSanitizer or UndefinedBehaviorSanitizer.
|
||||||
//
|
//
|
||||||
// Empty lines and lines starting with "#" are ignored. All the rest lines
|
// Empty lines and lines starting with "#" are ignored. Sections are defined
|
||||||
// should have the form:
|
// using a '[section_name]' header and can be used to specify sanitizers the
|
||||||
// section:wildcard_expression[=category]
|
// entries below it apply to. Section names are regular expressions, and
|
||||||
|
// entries without a section header match all sections (e.g. an '[*]' header
|
||||||
|
// is assumed.)
|
||||||
|
// The remaining lines should have the form:
|
||||||
|
// prefix:wildcard_expression[=category]
|
||||||
// If category is not specified, it is assumed to be empty string.
|
// If category is not specified, it is assumed to be empty string.
|
||||||
// Definitions of "section" and "category" are sanitizer-specific. For example,
|
// Definitions of "prefix" and "category" are sanitizer-specific. For example,
|
||||||
// sanitizer blacklists support sections "src", "fun" and "global".
|
// sanitizer blacklists support prefixes "src", "fun" and "global".
|
||||||
// Wildcard expressions define, respectively, source files, functions or
|
// Wildcard expressions define, respectively, source files, functions or
|
||||||
// globals which shouldn't be instrumented.
|
// globals which shouldn't be instrumented.
|
||||||
// Examples of categories:
|
// Examples of categories:
|
||||||
@ -26,6 +30,7 @@
|
|||||||
// detection for certain globals or source files.
|
// detection for certain globals or source files.
|
||||||
// Full special case list file example:
|
// Full special case list file example:
|
||||||
// ---
|
// ---
|
||||||
|
// [address]
|
||||||
// # Blacklisted items:
|
// # Blacklisted items:
|
||||||
// fun:*_ZN4base6subtle*
|
// fun:*_ZN4base6subtle*
|
||||||
// global:*global_with_bad_access_or_initialization*
|
// global:*global_with_bad_access_or_initialization*
|
||||||
@ -34,14 +39,13 @@
|
|||||||
// src:file_with_tricky_code.cc
|
// src:file_with_tricky_code.cc
|
||||||
// src:ignore-global-initializers-issues.cc=init
|
// src:ignore-global-initializers-issues.cc=init
|
||||||
//
|
//
|
||||||
|
// [dataflow]
|
||||||
// # Functions with pure functional semantics:
|
// # Functions with pure functional semantics:
|
||||||
// fun:cos=functional
|
// fun:cos=functional
|
||||||
// fun:sin=functional
|
// fun:sin=functional
|
||||||
// ---
|
// ---
|
||||||
// Note that the wild card is in fact an llvm::Regex, but * is automatically
|
// Note that the wild card is in fact an llvm::Regex, but * is automatically
|
||||||
// replaced with .*
|
// replaced with .*
|
||||||
// This is similar to the "ignore" feature of ThreadSanitizer.
|
|
||||||
// http://code.google.com/p/data-race-test/wiki/ThreadSanitizerIgnores
|
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
@ -49,6 +53,9 @@
|
|||||||
#define LLVM_SUPPORT_SPECIALCASELIST_H
|
#define LLVM_SUPPORT_SPECIALCASELIST_H
|
||||||
|
|
||||||
#include "llvm/ADT/StringMap.h"
|
#include "llvm/ADT/StringMap.h"
|
||||||
|
#include "llvm/ADT/StringSet.h"
|
||||||
|
#include "llvm/Support/Regex.h"
|
||||||
|
#include "llvm/Support/TrigramIndex.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -76,26 +83,63 @@ public:
|
|||||||
|
|
||||||
/// Returns true, if special case list contains a line
|
/// Returns true, if special case list contains a line
|
||||||
/// \code
|
/// \code
|
||||||
/// @Section:<E>=@Category
|
/// @Prefix:<E>=@Category
|
||||||
/// \endcode
|
/// \endcode
|
||||||
/// and @Query satisfies a wildcard expression <E>.
|
/// where @Query satisfies wildcard expression <E> in a given @Section.
|
||||||
bool inSection(StringRef Section, StringRef Query,
|
bool inSection(StringRef Section, StringRef Prefix, StringRef Query,
|
||||||
StringRef Category = StringRef()) const;
|
StringRef Category = StringRef()) const;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
|
// Implementations of the create*() functions that can also be used by derived
|
||||||
|
// classes.
|
||||||
|
bool createInternal(const std::vector<std::string> &Paths,
|
||||||
|
std::string &Error);
|
||||||
|
bool createInternal(const MemoryBuffer *MB, std::string &Error);
|
||||||
|
|
||||||
SpecialCaseList(SpecialCaseList const &) = delete;
|
SpecialCaseList(SpecialCaseList const &) = delete;
|
||||||
SpecialCaseList &operator=(SpecialCaseList const &) = delete;
|
SpecialCaseList &operator=(SpecialCaseList const &) = delete;
|
||||||
|
|
||||||
struct Entry;
|
/// Represents a set of regular expressions. Regular expressions which are
|
||||||
StringMap<StringMap<Entry>> Entries;
|
/// "literal" (i.e. no regex metacharacters) are stored in Strings, while all
|
||||||
StringMap<StringMap<std::string>> Regexps;
|
/// others are represented as a single pipe-separated regex in RegEx. The
|
||||||
|
/// reason for doing so is efficiency; StringSet is much faster at matching
|
||||||
|
/// literal strings than Regex.
|
||||||
|
class Matcher {
|
||||||
|
public:
|
||||||
|
bool insert(std::string Regexp, std::string &REError);
|
||||||
|
void compile();
|
||||||
|
bool match(StringRef Query) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
StringSet<> Strings;
|
||||||
|
TrigramIndex Trigrams;
|
||||||
|
std::unique_ptr<Regex> RegEx;
|
||||||
|
std::string UncompiledRegEx;
|
||||||
|
};
|
||||||
|
|
||||||
|
using SectionEntries = StringMap<StringMap<Matcher>>;
|
||||||
|
|
||||||
|
struct Section {
|
||||||
|
Section(std::unique_ptr<Matcher> M) : SectionMatcher(std::move(M)){};
|
||||||
|
|
||||||
|
std::unique_ptr<Matcher> SectionMatcher;
|
||||||
|
SectionEntries Entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Section> Sections;
|
||||||
bool IsCompiled;
|
bool IsCompiled;
|
||||||
|
|
||||||
SpecialCaseList();
|
SpecialCaseList();
|
||||||
/// Parses just-constructed SpecialCaseList entries from a memory buffer.
|
/// Parses just-constructed SpecialCaseList entries from a memory buffer.
|
||||||
bool parse(const MemoryBuffer *MB, std::string &Error);
|
bool parse(const MemoryBuffer *MB, StringMap<size_t> &SectionsMap,
|
||||||
|
std::string &Error);
|
||||||
/// compile() should be called once, after parsing all the memory buffers.
|
/// compile() should be called once, after parsing all the memory buffers.
|
||||||
void compile();
|
void compile();
|
||||||
|
|
||||||
|
// Helper method for derived classes to search by Prefix, Query, and Category
|
||||||
|
// once they have already resolved a section entry.
|
||||||
|
bool inSection(const SectionEntries &Entries, StringRef Prefix,
|
||||||
|
StringRef Query, StringRef Category) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace llvm
|
} // namespace llvm
|
||||||
|
@ -17,65 +17,72 @@
|
|||||||
#include "llvm/Support/SpecialCaseList.h"
|
#include "llvm/Support/SpecialCaseList.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/StringExtras.h"
|
#include "llvm/ADT/StringExtras.h"
|
||||||
#include "llvm/ADT/StringSet.h"
|
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
#include "llvm/Support/Regex.h"
|
#include "llvm/Support/Regex.h"
|
||||||
#include "llvm/Support/TrigramIndex.h"
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
/// Represents a set of regular expressions. Regular expressions which are
|
bool SpecialCaseList::Matcher::insert(std::string Regexp,
|
||||||
/// "literal" (i.e. no regex metacharacters) are stored in Strings, while all
|
std::string &REError) {
|
||||||
/// others are represented as a single pipe-separated regex in RegEx. The
|
if (Regex::isLiteralERE(Regexp)) {
|
||||||
/// reason for doing so is efficiency; StringSet is much faster at matching
|
Strings.insert(Regexp);
|
||||||
/// literal strings than Regex.
|
return true;
|
||||||
struct SpecialCaseList::Entry {
|
|
||||||
StringSet<> Strings;
|
|
||||||
TrigramIndex Trigrams;
|
|
||||||
std::unique_ptr<Regex> RegEx;
|
|
||||||
|
|
||||||
bool match(StringRef Query) const {
|
|
||||||
if (Strings.count(Query))
|
|
||||||
return true;
|
|
||||||
if (Trigrams.isDefinitelyOut(Query))
|
|
||||||
return false;
|
|
||||||
return RegEx && RegEx->match(Query);
|
|
||||||
}
|
}
|
||||||
};
|
Trigrams.insert(Regexp);
|
||||||
|
|
||||||
SpecialCaseList::SpecialCaseList() : Entries(), Regexps(), IsCompiled(false) {}
|
// Replace * with .*
|
||||||
|
for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std::string::npos;
|
||||||
|
pos += strlen(".*")) {
|
||||||
|
Regexp.replace(pos, strlen("*"), ".*");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the regexp is valid.
|
||||||
|
Regex CheckRE(Regexp);
|
||||||
|
if (!CheckRE.isValid(REError))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!UncompiledRegEx.empty())
|
||||||
|
UncompiledRegEx += "|";
|
||||||
|
UncompiledRegEx += "^(" + Regexp + ")$";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpecialCaseList::Matcher::compile() {
|
||||||
|
if (!UncompiledRegEx.empty()) {
|
||||||
|
RegEx.reset(new Regex(UncompiledRegEx));
|
||||||
|
UncompiledRegEx.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpecialCaseList::Matcher::match(StringRef Query) const {
|
||||||
|
if (Strings.count(Query))
|
||||||
|
return true;
|
||||||
|
if (Trigrams.isDefinitelyOut(Query))
|
||||||
|
return false;
|
||||||
|
return RegEx && RegEx->match(Query);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpecialCaseList::SpecialCaseList() : Sections(), IsCompiled(false) {}
|
||||||
|
|
||||||
std::unique_ptr<SpecialCaseList>
|
std::unique_ptr<SpecialCaseList>
|
||||||
SpecialCaseList::create(const std::vector<std::string> &Paths,
|
SpecialCaseList::create(const std::vector<std::string> &Paths,
|
||||||
std::string &Error) {
|
std::string &Error) {
|
||||||
std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList());
|
std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList());
|
||||||
for (const auto &Path : Paths) {
|
if (SCL->createInternal(Paths, Error))
|
||||||
ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
|
return SCL;
|
||||||
MemoryBuffer::getFile(Path);
|
return nullptr;
|
||||||
if (std::error_code EC = FileOrErr.getError()) {
|
|
||||||
Error = (Twine("can't open file '") + Path + "': " + EC.message()).str();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
std::string ParseError;
|
|
||||||
if (!SCL->parse(FileOrErr.get().get(), ParseError)) {
|
|
||||||
Error = (Twine("error parsing file '") + Path + "': " + ParseError).str();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SCL->compile();
|
|
||||||
return SCL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<SpecialCaseList> SpecialCaseList::create(const MemoryBuffer *MB,
|
std::unique_ptr<SpecialCaseList> SpecialCaseList::create(const MemoryBuffer *MB,
|
||||||
std::string &Error) {
|
std::string &Error) {
|
||||||
std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList());
|
std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList());
|
||||||
if (!SCL->parse(MB, Error))
|
if (SCL->createInternal(MB, Error))
|
||||||
return nullptr;
|
return SCL;
|
||||||
SCL->compile();
|
return nullptr;
|
||||||
return SCL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<SpecialCaseList>
|
std::unique_ptr<SpecialCaseList>
|
||||||
@ -86,15 +93,71 @@ SpecialCaseList::createOrDie(const std::vector<std::string> &Paths) {
|
|||||||
report_fatal_error(Error);
|
report_fatal_error(Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpecialCaseList::parse(const MemoryBuffer *MB, std::string &Error) {
|
bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths,
|
||||||
|
std::string &Error) {
|
||||||
|
StringMap<size_t> Sections;
|
||||||
|
for (const auto &Path : Paths) {
|
||||||
|
ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
|
||||||
|
MemoryBuffer::getFile(Path);
|
||||||
|
if (std::error_code EC = FileOrErr.getError()) {
|
||||||
|
Error = (Twine("can't open file '") + Path + "': " + EC.message()).str();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string ParseError;
|
||||||
|
if (!parse(FileOrErr.get().get(), Sections, ParseError)) {
|
||||||
|
Error = (Twine("error parsing file '") + Path + "': " + ParseError).str();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compile();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpecialCaseList::createInternal(const MemoryBuffer *MB,
|
||||||
|
std::string &Error) {
|
||||||
|
StringMap<size_t> Sections;
|
||||||
|
if (!parse(MB, Sections, Error))
|
||||||
|
return false;
|
||||||
|
compile();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpecialCaseList::parse(const MemoryBuffer *MB,
|
||||||
|
StringMap<size_t> &SectionsMap,
|
||||||
|
std::string &Error) {
|
||||||
// Iterate through each line in the blacklist file.
|
// Iterate through each line in the blacklist file.
|
||||||
SmallVector<StringRef, 16> Lines;
|
SmallVector<StringRef, 16> Lines;
|
||||||
SplitString(MB->getBuffer(), Lines, "\n\r");
|
SplitString(MB->getBuffer(), Lines, "\n\r");
|
||||||
|
|
||||||
int LineNo = 1;
|
int LineNo = 1;
|
||||||
|
StringRef Section = "*";
|
||||||
for (auto I = Lines.begin(), E = Lines.end(); I != E; ++I, ++LineNo) {
|
for (auto I = Lines.begin(), E = Lines.end(); I != E; ++I, ++LineNo) {
|
||||||
// Ignore empty lines and lines starting with "#"
|
// Ignore empty lines and lines starting with "#"
|
||||||
if (I->empty() || I->startswith("#"))
|
if (I->empty() || I->startswith("#"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Save section names
|
||||||
|
if (I->startswith("[")) {
|
||||||
|
if (!I->endswith("]")) {
|
||||||
|
Error = (Twine("malformed section header on line ") + Twine(LineNo) +
|
||||||
|
": " + *I).str();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Section = I->slice(1, I->size() - 1);
|
||||||
|
|
||||||
|
std::string REError;
|
||||||
|
Regex CheckRE(Section);
|
||||||
|
if (!CheckRE.isValid(REError)) {
|
||||||
|
Error =
|
||||||
|
(Twine("malformed regex for section ") + Section + ": '" + REError)
|
||||||
|
.str();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Get our prefix and unparsed regexp.
|
// Get our prefix and unparsed regexp.
|
||||||
std::pair<StringRef, StringRef> SplitLine = I->split(":");
|
std::pair<StringRef, StringRef> SplitLine = I->split(":");
|
||||||
StringRef Prefix = SplitLine.first;
|
StringRef Prefix = SplitLine.first;
|
||||||
@ -109,61 +172,62 @@ bool SpecialCaseList::parse(const MemoryBuffer *MB, std::string &Error) {
|
|||||||
std::string Regexp = SplitRegexp.first;
|
std::string Regexp = SplitRegexp.first;
|
||||||
StringRef Category = SplitRegexp.second;
|
StringRef Category = SplitRegexp.second;
|
||||||
|
|
||||||
// See if we can store Regexp in Strings.
|
// Create this section if it has not been seen before.
|
||||||
auto &Entry = Entries[Prefix][Category];
|
if (SectionsMap.find(Section) == SectionsMap.end()) {
|
||||||
if (Regex::isLiteralERE(Regexp)) {
|
std::unique_ptr<Matcher> M = make_unique<Matcher>();
|
||||||
Entry.Strings.insert(Regexp);
|
std::string REError;
|
||||||
continue;
|
if (!M->insert(Section, REError)) {
|
||||||
}
|
Error = (Twine("malformed section ") + Section + ": '" + REError).str();
|
||||||
Entry.Trigrams.insert(Regexp);
|
return false;
|
||||||
|
}
|
||||||
|
M->compile();
|
||||||
|
|
||||||
// Replace * with .*
|
SectionsMap[Section] = Sections.size();
|
||||||
for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std::string::npos;
|
Sections.emplace_back(std::move(M));
|
||||||
pos += strlen(".*")) {
|
|
||||||
Regexp.replace(pos, strlen("*"), ".*");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the regexp is valid.
|
auto &Entry = Sections[SectionsMap[Section]].Entries[Prefix][Category];
|
||||||
Regex CheckRE(Regexp);
|
|
||||||
std::string REError;
|
std::string REError;
|
||||||
if (!CheckRE.isValid(REError)) {
|
if (!Entry.insert(std::move(Regexp), REError)) {
|
||||||
Error = (Twine("malformed regex in line ") + Twine(LineNo) + ": '" +
|
Error = (Twine("malformed regex in line ") + Twine(LineNo) + ": '" +
|
||||||
SplitLine.second + "': " + REError).str();
|
SplitLine.second + "': " + REError).str();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add this regexp into the proper group by its prefix.
|
|
||||||
if (!Regexps[Prefix][Category].empty())
|
|
||||||
Regexps[Prefix][Category] += "|";
|
|
||||||
Regexps[Prefix][Category] += "^" + Regexp + "$";
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpecialCaseList::compile() {
|
void SpecialCaseList::compile() {
|
||||||
assert(!IsCompiled && "compile() should only be called once");
|
assert(!IsCompiled && "compile() should only be called once");
|
||||||
// Iterate through each of the prefixes, and create Regexs for them.
|
// Iterate through every section compiling regular expressions for every query
|
||||||
for (StringMap<StringMap<std::string>>::const_iterator I = Regexps.begin(),
|
// and creating Section entries.
|
||||||
E = Regexps.end();
|
for (auto &Section : Sections)
|
||||||
I != E; ++I) {
|
for (auto &Prefix : Section.Entries)
|
||||||
for (StringMap<std::string>::const_iterator II = I->second.begin(),
|
for (auto &Category : Prefix.getValue())
|
||||||
IE = I->second.end();
|
Category.getValue().compile();
|
||||||
II != IE; ++II) {
|
|
||||||
Entries[I->getKey()][II->getKey()].RegEx.reset(new Regex(II->getValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Regexps.clear();
|
|
||||||
IsCompiled = true;
|
IsCompiled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpecialCaseList::~SpecialCaseList() {}
|
SpecialCaseList::~SpecialCaseList() {}
|
||||||
|
|
||||||
bool SpecialCaseList::inSection(StringRef Section, StringRef Query,
|
bool SpecialCaseList::inSection(StringRef Section, StringRef Prefix,
|
||||||
StringRef Category) const {
|
StringRef Query, StringRef Category) const {
|
||||||
assert(IsCompiled && "SpecialCaseList::compile() was not called!");
|
assert(IsCompiled && "SpecialCaseList::compile() was not called!");
|
||||||
StringMap<StringMap<Entry> >::const_iterator I = Entries.find(Section);
|
|
||||||
|
for (auto &SectionIter : Sections)
|
||||||
|
if (SectionIter.SectionMatcher->match(Section) &&
|
||||||
|
inSection(SectionIter.Entries, Prefix, Query, Category))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpecialCaseList::inSection(const SectionEntries &Entries, StringRef Prefix,
|
||||||
|
StringRef Query, StringRef Category) const {
|
||||||
|
SectionEntries::const_iterator I = Entries.find(Prefix);
|
||||||
if (I == Entries.end()) return false;
|
if (I == Entries.end()) return false;
|
||||||
StringMap<Entry>::const_iterator II = I->second.find(Category);
|
StringMap<Matcher>::const_iterator II = I->second.find(Category);
|
||||||
if (II == I->second.end()) return false;
|
if (II == I->second.end()) return false;
|
||||||
|
|
||||||
return II->getValue().match(Query);
|
return II->getValue().match(Query);
|
||||||
|
@ -155,7 +155,7 @@ class DFSanABIList {
|
|||||||
/// given category.
|
/// given category.
|
||||||
bool isIn(const Function &F, StringRef Category) const {
|
bool isIn(const Function &F, StringRef Category) const {
|
||||||
return isIn(*F.getParent(), Category) ||
|
return isIn(*F.getParent(), Category) ||
|
||||||
SCL->inSection("fun", F.getName(), Category);
|
SCL->inSection("dataflow", "fun", F.getName(), Category);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this global alias is listed in the given category.
|
/// Returns whether this global alias is listed in the given category.
|
||||||
@ -167,15 +167,16 @@ class DFSanABIList {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (isa<FunctionType>(GA.getValueType()))
|
if (isa<FunctionType>(GA.getValueType()))
|
||||||
return SCL->inSection("fun", GA.getName(), Category);
|
return SCL->inSection("dataflow", "fun", GA.getName(), Category);
|
||||||
|
|
||||||
return SCL->inSection("global", GA.getName(), Category) ||
|
return SCL->inSection("dataflow", "global", GA.getName(), Category) ||
|
||||||
SCL->inSection("type", GetGlobalTypeString(GA), Category);
|
SCL->inSection("dataflow", "type", GetGlobalTypeString(GA),
|
||||||
|
Category);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this module is listed in the given category.
|
/// Returns whether this module is listed in the given category.
|
||||||
bool isIn(const Module &M, StringRef Category) const {
|
bool isIn(const Module &M, StringRef Category) const {
|
||||||
return SCL->inSection("src", M.getModuleIdentifier(), Category);
|
return SCL->inSection("dataflow", "src", M.getModuleIdentifier(), Category);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ bool NameRegexCoverageFilter::matches(
|
|||||||
bool NameWhitelistCoverageFilter::matches(
|
bool NameWhitelistCoverageFilter::matches(
|
||||||
const coverage::CoverageMapping &,
|
const coverage::CoverageMapping &,
|
||||||
const coverage::FunctionRecord &Function) {
|
const coverage::FunctionRecord &Function) {
|
||||||
return Whitelist.inSection("whitelist_fun", Function.Name);
|
return Whitelist.inSection("llvmcov", "whitelist_fun", Function.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegionCoverageFilter::matches(const coverage::CoverageMapping &CM,
|
bool RegionCoverageFilter::matches(const coverage::CoverageMapping &CM,
|
||||||
|
@ -584,13 +584,16 @@ public:
|
|||||||
UserBlacklist(createUserBlacklist()) {}
|
UserBlacklist(createUserBlacklist()) {}
|
||||||
|
|
||||||
bool isBlacklisted(const DILineInfo &I) {
|
bool isBlacklisted(const DILineInfo &I) {
|
||||||
if (DefaultBlacklist && DefaultBlacklist->inSection("fun", I.FunctionName))
|
if (DefaultBlacklist &&
|
||||||
|
DefaultBlacklist->inSection("sancov", "fun", I.FunctionName))
|
||||||
return true;
|
return true;
|
||||||
if (DefaultBlacklist && DefaultBlacklist->inSection("src", I.FileName))
|
if (DefaultBlacklist &&
|
||||||
|
DefaultBlacklist->inSection("sancov", "src", I.FileName))
|
||||||
return true;
|
return true;
|
||||||
if (UserBlacklist && UserBlacklist->inSection("fun", I.FunctionName))
|
if (UserBlacklist &&
|
||||||
|
UserBlacklist->inSection("sancov", "fun", I.FunctionName))
|
||||||
return true;
|
return true;
|
||||||
if (UserBlacklist && UserBlacklist->inSection("src", I.FileName))
|
if (UserBlacklist && UserBlacklist->inSection("sancov", "src", I.FileName))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -51,47 +51,75 @@ TEST_F(SpecialCaseListTest, Basic) {
|
|||||||
"src:bye\n"
|
"src:bye\n"
|
||||||
"src:hi=category\n"
|
"src:hi=category\n"
|
||||||
"src:z*=category\n");
|
"src:z*=category\n");
|
||||||
EXPECT_TRUE(SCL->inSection("src", "hello"));
|
EXPECT_TRUE(SCL->inSection("", "src", "hello"));
|
||||||
EXPECT_TRUE(SCL->inSection("src", "bye"));
|
EXPECT_TRUE(SCL->inSection("", "src", "bye"));
|
||||||
EXPECT_TRUE(SCL->inSection("src", "hi", "category"));
|
EXPECT_TRUE(SCL->inSection("", "src", "hi", "category"));
|
||||||
EXPECT_TRUE(SCL->inSection("src", "zzzz", "category"));
|
EXPECT_TRUE(SCL->inSection("", "src", "zzzz", "category"));
|
||||||
EXPECT_FALSE(SCL->inSection("src", "hi"));
|
EXPECT_FALSE(SCL->inSection("", "src", "hi"));
|
||||||
EXPECT_FALSE(SCL->inSection("fun", "hello"));
|
EXPECT_FALSE(SCL->inSection("", "fun", "hello"));
|
||||||
EXPECT_FALSE(SCL->inSection("src", "hello", "category"));
|
EXPECT_FALSE(SCL->inSection("", "src", "hello", "category"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpecialCaseListTest, SectionRegexErrorHandling) {
|
||||||
|
std::string Error;
|
||||||
|
EXPECT_EQ(makeSpecialCaseList("[address", Error), nullptr);
|
||||||
|
EXPECT_TRUE(((StringRef)Error).startswith("malformed section header "));
|
||||||
|
|
||||||
|
EXPECT_EQ(makeSpecialCaseList("[[]", Error), nullptr);
|
||||||
|
EXPECT_TRUE(((StringRef)Error).startswith("malformed regex for section [: "));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpecialCaseListTest, Section) {
|
||||||
|
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:global\n"
|
||||||
|
"[sect1|sect2]\n"
|
||||||
|
"src:test1\n"
|
||||||
|
"[sect3*]\n"
|
||||||
|
"src:test2\n");
|
||||||
|
EXPECT_TRUE(SCL->inSection("arbitrary", "src", "global"));
|
||||||
|
EXPECT_TRUE(SCL->inSection("", "src", "global"));
|
||||||
|
EXPECT_TRUE(SCL->inSection("sect1", "src", "test1"));
|
||||||
|
EXPECT_FALSE(SCL->inSection("sect1-arbitrary", "src", "test1"));
|
||||||
|
EXPECT_FALSE(SCL->inSection("sect", "src", "test1"));
|
||||||
|
EXPECT_FALSE(SCL->inSection("sect1", "src", "test2"));
|
||||||
|
EXPECT_TRUE(SCL->inSection("sect2", "src", "test1"));
|
||||||
|
EXPECT_TRUE(SCL->inSection("sect3", "src", "test2"));
|
||||||
|
EXPECT_TRUE(SCL->inSection("sect3-arbitrary", "src", "test2"));
|
||||||
|
EXPECT_FALSE(SCL->inSection("", "src", "test1"));
|
||||||
|
EXPECT_FALSE(SCL->inSection("", "src", "test2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpecialCaseListTest, GlobalInit) {
|
TEST_F(SpecialCaseListTest, GlobalInit) {
|
||||||
std::unique_ptr<SpecialCaseList> SCL =
|
std::unique_ptr<SpecialCaseList> SCL =
|
||||||
makeSpecialCaseList("global:foo=init\n");
|
makeSpecialCaseList("global:foo=init\n");
|
||||||
EXPECT_FALSE(SCL->inSection("global", "foo"));
|
EXPECT_FALSE(SCL->inSection("", "global", "foo"));
|
||||||
EXPECT_FALSE(SCL->inSection("global", "bar"));
|
EXPECT_FALSE(SCL->inSection("", "global", "bar"));
|
||||||
EXPECT_TRUE(SCL->inSection("global", "foo", "init"));
|
EXPECT_TRUE(SCL->inSection("", "global", "foo", "init"));
|
||||||
EXPECT_FALSE(SCL->inSection("global", "bar", "init"));
|
EXPECT_FALSE(SCL->inSection("", "global", "bar", "init"));
|
||||||
|
|
||||||
SCL = makeSpecialCaseList("type:t2=init\n");
|
SCL = makeSpecialCaseList("type:t2=init\n");
|
||||||
EXPECT_FALSE(SCL->inSection("type", "t1"));
|
EXPECT_FALSE(SCL->inSection("", "type", "t1"));
|
||||||
EXPECT_FALSE(SCL->inSection("type", "t2"));
|
EXPECT_FALSE(SCL->inSection("", "type", "t2"));
|
||||||
EXPECT_FALSE(SCL->inSection("type", "t1", "init"));
|
EXPECT_FALSE(SCL->inSection("", "type", "t1", "init"));
|
||||||
EXPECT_TRUE(SCL->inSection("type", "t2", "init"));
|
EXPECT_TRUE(SCL->inSection("", "type", "t2", "init"));
|
||||||
|
|
||||||
SCL = makeSpecialCaseList("src:hello=init\n");
|
SCL = makeSpecialCaseList("src:hello=init\n");
|
||||||
EXPECT_FALSE(SCL->inSection("src", "hello"));
|
EXPECT_FALSE(SCL->inSection("", "src", "hello"));
|
||||||
EXPECT_FALSE(SCL->inSection("src", "bye"));
|
EXPECT_FALSE(SCL->inSection("", "src", "bye"));
|
||||||
EXPECT_TRUE(SCL->inSection("src", "hello", "init"));
|
EXPECT_TRUE(SCL->inSection("", "src", "hello", "init"));
|
||||||
EXPECT_FALSE(SCL->inSection("src", "bye", "init"));
|
EXPECT_FALSE(SCL->inSection("", "src", "bye", "init"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpecialCaseListTest, Substring) {
|
TEST_F(SpecialCaseListTest, Substring) {
|
||||||
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:hello\n"
|
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:hello\n"
|
||||||
"fun:foo\n"
|
"fun:foo\n"
|
||||||
"global:bar\n");
|
"global:bar\n");
|
||||||
EXPECT_FALSE(SCL->inSection("src", "othello"));
|
EXPECT_FALSE(SCL->inSection("", "src", "othello"));
|
||||||
EXPECT_FALSE(SCL->inSection("fun", "tomfoolery"));
|
EXPECT_FALSE(SCL->inSection("", "fun", "tomfoolery"));
|
||||||
EXPECT_FALSE(SCL->inSection("global", "bartender"));
|
EXPECT_FALSE(SCL->inSection("", "global", "bartender"));
|
||||||
|
|
||||||
SCL = makeSpecialCaseList("fun:*foo*\n");
|
SCL = makeSpecialCaseList("fun:*foo*\n");
|
||||||
EXPECT_TRUE(SCL->inSection("fun", "tomfoolery"));
|
EXPECT_TRUE(SCL->inSection("", "fun", "tomfoolery"));
|
||||||
EXPECT_TRUE(SCL->inSection("fun", "foobar"));
|
EXPECT_TRUE(SCL->inSection("", "fun", "foobar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpecialCaseListTest, InvalidSpecialCaseList) {
|
TEST_F(SpecialCaseListTest, InvalidSpecialCaseList) {
|
||||||
@ -113,7 +141,7 @@ TEST_F(SpecialCaseListTest, InvalidSpecialCaseList) {
|
|||||||
|
|
||||||
TEST_F(SpecialCaseListTest, EmptySpecialCaseList) {
|
TEST_F(SpecialCaseListTest, EmptySpecialCaseList) {
|
||||||
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("");
|
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("");
|
||||||
EXPECT_FALSE(SCL->inSection("foo", "bar"));
|
EXPECT_FALSE(SCL->inSection("", "foo", "bar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpecialCaseListTest, MultipleBlacklists) {
|
TEST_F(SpecialCaseListTest, MultipleBlacklists) {
|
||||||
@ -124,12 +152,12 @@ TEST_F(SpecialCaseListTest, MultipleBlacklists) {
|
|||||||
Files.push_back(makeSpecialCaseListFile("src:baz\n"
|
Files.push_back(makeSpecialCaseListFile("src:baz\n"
|
||||||
"src:*fog*\n"));
|
"src:*fog*\n"));
|
||||||
auto SCL = SpecialCaseList::createOrDie(Files);
|
auto SCL = SpecialCaseList::createOrDie(Files);
|
||||||
EXPECT_TRUE(SCL->inSection("src", "bar"));
|
EXPECT_TRUE(SCL->inSection("", "src", "bar"));
|
||||||
EXPECT_TRUE(SCL->inSection("src", "baz"));
|
EXPECT_TRUE(SCL->inSection("", "src", "baz"));
|
||||||
EXPECT_FALSE(SCL->inSection("src", "ban"));
|
EXPECT_FALSE(SCL->inSection("", "src", "ban"));
|
||||||
EXPECT_TRUE(SCL->inSection("src", "ban", "init"));
|
EXPECT_TRUE(SCL->inSection("", "src", "ban", "init"));
|
||||||
EXPECT_TRUE(SCL->inSection("src", "tomfoolery"));
|
EXPECT_TRUE(SCL->inSection("", "src", "tomfoolery"));
|
||||||
EXPECT_TRUE(SCL->inSection("src", "tomfoglery"));
|
EXPECT_TRUE(SCL->inSection("", "src", "tomfoglery"));
|
||||||
for (auto &Path : Files)
|
for (auto &Path : Files)
|
||||||
sys::fs::remove(Path);
|
sys::fs::remove(Path);
|
||||||
}
|
}
|
||||||
@ -137,35 +165,35 @@ TEST_F(SpecialCaseListTest, MultipleBlacklists) {
|
|||||||
TEST_F(SpecialCaseListTest, NoTrigramsInRules) {
|
TEST_F(SpecialCaseListTest, NoTrigramsInRules) {
|
||||||
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:b.r\n"
|
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:b.r\n"
|
||||||
"fun:za*az\n");
|
"fun:za*az\n");
|
||||||
EXPECT_TRUE(SCL->inSection("fun", "bar"));
|
EXPECT_TRUE(SCL->inSection("", "fun", "bar"));
|
||||||
EXPECT_FALSE(SCL->inSection("fun", "baz"));
|
EXPECT_FALSE(SCL->inSection("", "fun", "baz"));
|
||||||
EXPECT_TRUE(SCL->inSection("fun", "zakaz"));
|
EXPECT_TRUE(SCL->inSection("", "fun", "zakaz"));
|
||||||
EXPECT_FALSE(SCL->inSection("fun", "zaraza"));
|
EXPECT_FALSE(SCL->inSection("", "fun", "zaraza"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpecialCaseListTest, NoTrigramsInARule) {
|
TEST_F(SpecialCaseListTest, NoTrigramsInARule) {
|
||||||
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*bar*\n"
|
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*bar*\n"
|
||||||
"fun:za*az\n");
|
"fun:za*az\n");
|
||||||
EXPECT_TRUE(SCL->inSection("fun", "abara"));
|
EXPECT_TRUE(SCL->inSection("", "fun", "abara"));
|
||||||
EXPECT_FALSE(SCL->inSection("fun", "bor"));
|
EXPECT_FALSE(SCL->inSection("", "fun", "bor"));
|
||||||
EXPECT_TRUE(SCL->inSection("fun", "zakaz"));
|
EXPECT_TRUE(SCL->inSection("", "fun", "zakaz"));
|
||||||
EXPECT_FALSE(SCL->inSection("fun", "zaraza"));
|
EXPECT_FALSE(SCL->inSection("", "fun", "zaraza"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpecialCaseListTest, RepetitiveRule) {
|
TEST_F(SpecialCaseListTest, RepetitiveRule) {
|
||||||
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*bar*bar*bar*bar*\n"
|
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*bar*bar*bar*bar*\n"
|
||||||
"fun:bar*\n");
|
"fun:bar*\n");
|
||||||
EXPECT_TRUE(SCL->inSection("fun", "bara"));
|
EXPECT_TRUE(SCL->inSection("", "fun", "bara"));
|
||||||
EXPECT_FALSE(SCL->inSection("fun", "abara"));
|
EXPECT_FALSE(SCL->inSection("", "fun", "abara"));
|
||||||
EXPECT_TRUE(SCL->inSection("fun", "barbarbarbar"));
|
EXPECT_TRUE(SCL->inSection("", "fun", "barbarbarbar"));
|
||||||
EXPECT_TRUE(SCL->inSection("fun", "abarbarbarbar"));
|
EXPECT_TRUE(SCL->inSection("", "fun", "abarbarbarbar"));
|
||||||
EXPECT_FALSE(SCL->inSection("fun", "abarbarbar"));
|
EXPECT_FALSE(SCL->inSection("", "fun", "abarbarbar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpecialCaseListTest, SpecialSymbolRule) {
|
TEST_F(SpecialCaseListTest, SpecialSymbolRule) {
|
||||||
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n");
|
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n");
|
||||||
EXPECT_TRUE(SCL->inSection("src", "c++abi"));
|
EXPECT_TRUE(SCL->inSection("", "src", "c++abi"));
|
||||||
EXPECT_FALSE(SCL->inSection("src", "c\\+\\+abi"));
|
EXPECT_FALSE(SCL->inSection("", "src", "c\\+\\+abi"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpecialCaseListTest, PopularTrigram) {
|
TEST_F(SpecialCaseListTest, PopularTrigram) {
|
||||||
@ -173,20 +201,20 @@ TEST_F(SpecialCaseListTest, PopularTrigram) {
|
|||||||
"fun:*aaaaa*\n"
|
"fun:*aaaaa*\n"
|
||||||
"fun:*aaaa*\n"
|
"fun:*aaaa*\n"
|
||||||
"fun:*aaa*\n");
|
"fun:*aaa*\n");
|
||||||
EXPECT_TRUE(SCL->inSection("fun", "aaa"));
|
EXPECT_TRUE(SCL->inSection("", "fun", "aaa"));
|
||||||
EXPECT_TRUE(SCL->inSection("fun", "aaaa"));
|
EXPECT_TRUE(SCL->inSection("", "fun", "aaaa"));
|
||||||
EXPECT_TRUE(SCL->inSection("fun", "aaaabbbaaa"));
|
EXPECT_TRUE(SCL->inSection("", "fun", "aaaabbbaaa"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpecialCaseListTest, EscapedSymbols) {
|
TEST_F(SpecialCaseListTest, EscapedSymbols) {
|
||||||
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n"
|
std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n"
|
||||||
"src:*hello\\\\world*\n");
|
"src:*hello\\\\world*\n");
|
||||||
EXPECT_TRUE(SCL->inSection("src", "dir/c++abi"));
|
EXPECT_TRUE(SCL->inSection("", "src", "dir/c++abi"));
|
||||||
EXPECT_FALSE(SCL->inSection("src", "dir/c\\+\\+abi"));
|
EXPECT_FALSE(SCL->inSection("", "src", "dir/c\\+\\+abi"));
|
||||||
EXPECT_FALSE(SCL->inSection("src", "c\\+\\+abi"));
|
EXPECT_FALSE(SCL->inSection("", "src", "c\\+\\+abi"));
|
||||||
EXPECT_TRUE(SCL->inSection("src", "C:\\hello\\world"));
|
EXPECT_TRUE(SCL->inSection("", "src", "C:\\hello\\world"));
|
||||||
EXPECT_TRUE(SCL->inSection("src", "hello\\world"));
|
EXPECT_TRUE(SCL->inSection("", "src", "hello\\world"));
|
||||||
EXPECT_FALSE(SCL->inSection("src", "hello\\\\world"));
|
EXPECT_FALSE(SCL->inSection("", "src", "hello\\\\world"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user