Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/SanitizerSpecialCaseList.rst
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ tool-specific docs.
# Lines starting with # are ignored.
# Turn off checks for the source file
# Entries without sections are placed into [*] and apply to all sanitizers
# On windows, "/" also matches "\" in filenames
src:path/to/source/file.c
src:*/source/file.c
# Turn off checks for this main file, including files included by it.
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Basic/Diagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,8 @@ bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId,
bool WarningsSpecialCaseList::globsMatches(
const llvm::StringMap<Matcher> &CategoriesToMatchers,
StringRef FilePath) const {
static bool HaveWindowsPathStyle =
llvm::sys::path::is_style_windows(llvm::sys::path::Style::native);
StringRef LongestMatch;
bool LongestIsPositive = false;
for (const auto &Entry : CategoriesToMatchers) {
Expand All @@ -631,7 +633,8 @@ bool WarningsSpecialCaseList::globsMatches(
for (const auto &Glob : Matcher.Globs) {
if (Glob->Name.size() < LongestMatch.size())
continue;
if (!Glob->Pattern.match(FilePath))
if (!Glob->Pattern.match(FilePath,
/*IsSlashAgnostic=*/HaveWindowsPathStyle))
continue;
LongestMatch = Glob->Name;
LongestIsPositive = IsPositive;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/SanitizerSpecialCaseList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ void SanitizerSpecialCaseList::createSanitizerSections() {
SanitizerMask Mask;

#define SANITIZER(NAME, ID) \
if (S.SectionMatcher->match(NAME)) \
if (S.SectionMatcher->match(NAME, /*IsFilename=*/false)) \
Mask |= SanitizerKind::ID;
#define SANITIZER_GROUP(NAME, ID, ALIAS) SANITIZER(NAME, ID)

Expand Down
28 changes: 28 additions & 0 deletions clang/unittests/Basic/DiagnosticTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,32 @@ TEST_F(SuppressionMappingTest, ParsingRespectsOtherWarningOpts) {
clang::ProcessWarningOptions(Diags, Diags.getDiagnosticOptions(), *FS);
EXPECT_THAT(diags(), IsEmpty());
}

#ifdef _WIN32
// We're only slash-agnostic on windows hosts
TEST_F(SuppressionMappingTest, TreatsFilesAsSlashAgnosticOnWindows) {
llvm::StringLiteral SuppressionMappingFile = R"(
[unused]
src:*clang/*
src:*clang/lib/Sema/*=emit
src:*clang/lib\\Sema/foo*
fun:suppress/me)";
Diags.getDiagnosticOptions().DiagnosticSuppressionMappingsFile = "foo.txt";
FS->addFile("foo.txt", /*ModificationTime=*/{},
llvm::MemoryBuffer::getMemBuffer(SuppressionMappingFile));
clang::ProcessWarningOptions(Diags, Diags.getDiagnosticOptions(), *FS);
EXPECT_THAT(diags(), IsEmpty());

EXPECT_TRUE(Diags.isSuppressedViaMapping(
diag::warn_unused_function, locForFile(R"(clang/lib/Basic/bar.h)")));
EXPECT_FALSE(Diags.isSuppressedViaMapping(
diag::warn_unused_function, locForFile(R"(clang/lib/Sema\baz.h)")));

// We require a literal backslash before "Sema"
EXPECT_TRUE(Diags.isSuppressedViaMapping(
diag::warn_unused_function, locForFile(R"(clang\lib\Sema/foo.h)")));
EXPECT_FALSE(Diags.isSuppressedViaMapping(
diag::warn_unused_function, locForFile(R"(clang/lib/Sema/foo.h)")));
}
#endif
} // namespace
4 changes: 4 additions & 0 deletions llvm/docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ Changes to BOLT
Changes to Sanitizers
---------------------

* On windows hosts, the [sanitizer special case list format](https://clang.llvm.org/docs/SanitizerSpecialCaseList.html#format)
now treats forward slashes in filenames as matching either a forward or a
backslash, to accommodate paths with mixed unix and windows styles.

Other Changes
-------------

Expand Down
8 changes: 6 additions & 2 deletions llvm/include/llvm/Support/GlobPattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ namespace llvm {
/// brace expansions are not supported and characters `{,}` are treated as
/// literals.
/// * `\` escapes the next character so it is treated as a literal.
/// * If \p IsSlashAgnostic is passed to the match function, then forward
/// slashes `/` also match backslashes `\`.
///
/// Some known edge cases are:
/// * The literal `]` is allowed as the first character in a character class,
Expand All @@ -57,8 +59,9 @@ class GlobPattern {
/// brace expansion
LLVM_ABI static Expected<GlobPattern>
create(StringRef Pat, std::optional<size_t> MaxSubPatterns = {});
/// \param IsSlashAgnostic whether to treat '/' as also matching '\'
/// \returns \p true if \p S matches this glob pattern
LLVM_ABI bool match(StringRef S) const;
LLVM_ABI bool match(StringRef S, bool IsSlashAgnostic = false) const;

// Returns true for glob pattern "*". Can be used to avoid expensive
// preparation/acquisition of the input for match().
Expand All @@ -76,8 +79,9 @@ class GlobPattern {
struct SubGlobPattern {
/// \param Pat the pattern to match against
LLVM_ABI static Expected<SubGlobPattern> create(StringRef Pat);
/// \param IsSlashAgnostic whether to treat '/' as also matching '\'
/// \returns \p true if \p S matches this glob pattern
LLVM_ABI bool match(StringRef S) const;
LLVM_ABI bool match(StringRef S, bool IsSlashAgnostic) const;
StringRef getPat() const { return StringRef(Pat.data(), Pat.size()); }

// Brackets with their end position and matched bytes.
Expand Down
5 changes: 3 additions & 2 deletions llvm/include/llvm/Support/SpecialCaseList.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,9 @@ class SpecialCaseList {
LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber,
bool UseRegex);
// Returns the line number in the source file that this query matches to.
// Returns zero if no match is found.
LLVM_ABI unsigned match(StringRef Query) const;
// On windows, treat '/' as also matching '\' in filenames when using globs.
// Returns zero if no match is found
LLVM_ABI unsigned match(StringRef Query, bool IsFilename) const;

struct Glob {
std::string Name;
Expand Down
13 changes: 9 additions & 4 deletions llvm/lib/Support/GlobPattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,21 +190,22 @@ GlobPattern::SubGlobPattern::create(StringRef S) {
return Pat;
}

bool GlobPattern::match(StringRef S) const {
bool GlobPattern::match(StringRef S, bool IsSlashAgnostic) const {
if (!S.consume_front(Prefix))
return false;
if (SubGlobs.empty() && S.empty())
return true;
for (auto &Glob : SubGlobs)
if (Glob.match(S))
if (Glob.match(S, IsSlashAgnostic))
return true;
return false;
}

// Factor the pattern into segments split by '*'. The segment is matched
// sequentianlly by finding the first occurrence past the end of the previous
// sequentially by finding the first occurrence past the end of the previous
// match.
bool GlobPattern::SubGlobPattern::match(StringRef Str) const {
bool GlobPattern::SubGlobPattern::match(StringRef Str,
bool IsSlashAgnostic) const {
const char *P = Pat.data(), *SegmentBegin = nullptr, *S = Str.data(),
*SavedS = S;
const char *const PEnd = P + Pat.size(), *const End = S + Str.size();
Expand All @@ -231,6 +232,10 @@ bool GlobPattern::SubGlobPattern::match(StringRef Str) const {
++S;
continue;
}
} else if (IsSlashAgnostic && *P == '/' && *S == '\\') {
++P;
++S;
continue;
} else if (*P == *S || *P == '?') {
++P;
++S;
Expand Down
15 changes: 11 additions & 4 deletions llvm/lib/Support/SpecialCaseList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <stdio.h>
#include <string>
Expand Down Expand Up @@ -66,9 +67,13 @@ Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber,
return Error::success();
}

unsigned SpecialCaseList::Matcher::match(StringRef Query) const {
unsigned SpecialCaseList::Matcher::match(StringRef Query,
bool IsFilename) const {
static bool HaveWindowsPathStyle =
llvm::sys::path::is_style_windows(llvm::sys::path::Style::native);
for (const auto &Glob : reverse(Globs))
if (Glob->Pattern.match(Query))
if (Glob->Pattern.match(
Query, /*IsSlashAgnostic=*/(HaveWindowsPathStyle && IsFilename)))
return Glob->LineNo;
for (const auto &[Regex, LineNumber] : reverse(RegExes))
if (Regex->match(Query))
Expand Down Expand Up @@ -218,7 +223,8 @@ std::pair<unsigned, unsigned>
SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix,
StringRef Query, StringRef Category) const {
for (const auto &S : reverse(Sections)) {
if (S.SectionMatcher->match(Section)) {
bool IsFilename = Prefix == "src" || Prefix == "mainfile";
if (S.SectionMatcher->match(Section, IsFilename)) {
unsigned Blame = inSectionBlame(S.Entries, Prefix, Query, Category);
if (Blame)
return {S.FileIdx, Blame};
Expand All @@ -237,7 +243,8 @@ unsigned SpecialCaseList::inSectionBlame(const SectionEntries &Entries,
if (II == I->second.end())
return 0;

return II->getValue().match(Query);
bool IsFilename = Prefix == "src" || Prefix == "mainfile";
return II->getValue().match(Query, IsFilename);
}

} // namespace llvm