Skip to content

Make sanitizer special case list slash-agnostic #149886

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
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
# "/" matches both windows and unix path separators ("/" and "\")
src:path/to/source/file.c
src:*/source/file.c
# Turn off checks for this main file, including files included by it.
Expand Down
23 changes: 23 additions & 0 deletions clang/unittests/Basic/DiagnosticTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,27 @@ TEST_F(SuppressionMappingTest, ParsingRespectsOtherWarningOpts) {
clang::ProcessWarningOptions(Diags, Diags.getDiagnosticOptions(), *FS);
EXPECT_THAT(diags(), IsEmpty());
}

TEST_F(SuppressionMappingTest, ForwardSlashMatchesBothDirections) {
llvm::StringLiteral SuppressionMappingFile = R"(
[unused]
src:*clang/*
src:*clang/lib/Sema/*=emit
src:*clang/lib\\Sema/foo*)";
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/foo.h)")));
EXPECT_FALSE(Diags.isSuppressedViaMapping(
diag::warn_unused_function, locForFile(R"(clang/lib/Sema\bar.h)")));
EXPECT_TRUE(Diags.isSuppressedViaMapping(
diag::warn_unused_function, locForFile(R"(clang\lib\Sema/foo.h)")));
// The third pattern requires a literal backslash before Sema
EXPECT_FALSE(Diags.isSuppressedViaMapping(
diag::warn_unused_function, locForFile(R"(clang/lib/Sema/foo.h)")));
}
} // namespace
4 changes: 4 additions & 0 deletions llvm/docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,10 @@ Changes to BOLT
Changes to Sanitizers
---------------------

* The [sanitizer special case list format](https://clang.llvm.org/docs/SanitizerSpecialCaseList.html#format)
now treats forward slashes as either a forward or a backslash, to handle
paths with mixed unix and window styles.

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

Expand Down
10 changes: 8 additions & 2 deletions llvm/include/llvm/Support/GlobPattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ namespace llvm {
/// expansions are not supported. If \p MaxSubPatterns is empty then
/// brace expansions are not supported and characters `{,}` are treated as
/// literals.
/// * `/` matches both unix and windows path separators: `/` and `\`.
/// * `\` escapes the next character so it is treated as a literal.
///
/// Some known edge cases are:
Expand All @@ -55,8 +56,10 @@ class GlobPattern {
/// \param MaxSubPatterns if provided limit the number of allowed subpatterns
/// created from expanding braces otherwise disable
/// brace expansion
/// \param IsSlashAgnostic whether to treat '/' as matching '\\' as well
LLVM_ABI static Expected<GlobPattern>
create(StringRef Pat, std::optional<size_t> MaxSubPatterns = {});
create(StringRef Pat, std::optional<size_t> MaxSubPatterns = {},
bool IsSlashAgnostic = false);
/// \returns \p true if \p S matches this glob pattern
LLVM_ABI bool match(StringRef S) const;

Expand All @@ -75,7 +78,9 @@ class GlobPattern {

struct SubGlobPattern {
/// \param Pat the pattern to match against
LLVM_ABI static Expected<SubGlobPattern> create(StringRef Pat);
/// \param SlashAgnostic whether to treat '/' as matching '\\' as well
LLVM_ABI static Expected<SubGlobPattern> create(StringRef Pat,
bool SlashAgnostic);
/// \returns \p true if \p S matches this glob pattern
LLVM_ABI bool match(StringRef S) const;
StringRef getPat() const { return StringRef(Pat.data(), Pat.size()); }
Expand All @@ -87,6 +92,7 @@ class GlobPattern {
};
SmallVector<Bracket, 0> Brackets;
SmallVector<char, 0> Pat;
bool IsSlashAgnostic;
};
SmallVector<SubGlobPattern, 1> SubGlobs;
};
Expand Down
14 changes: 10 additions & 4 deletions llvm/lib/Support/GlobPattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,9 @@ parseBraceExpansions(StringRef S, std::optional<size_t> MaxSubPatterns) {
return std::move(SubPatterns);
}

Expected<GlobPattern>
GlobPattern::create(StringRef S, std::optional<size_t> MaxSubPatterns) {
Expected<GlobPattern> GlobPattern::create(StringRef S,
std::optional<size_t> MaxSubPatterns,
bool IsSlashAgnostic) {
GlobPattern Pat;

// Store the prefix that does not contain any metacharacter.
Expand All @@ -147,7 +148,7 @@ GlobPattern::create(StringRef S, std::optional<size_t> MaxSubPatterns) {
if (auto Err = parseBraceExpansions(S, MaxSubPatterns).moveInto(SubPats))
return std::move(Err);
for (StringRef SubPat : SubPats) {
auto SubGlobOrErr = SubGlobPattern::create(SubPat);
auto SubGlobOrErr = SubGlobPattern::create(SubPat, IsSlashAgnostic);
if (!SubGlobOrErr)
return SubGlobOrErr.takeError();
Pat.SubGlobs.push_back(*SubGlobOrErr);
Expand All @@ -157,8 +158,9 @@ GlobPattern::create(StringRef S, std::optional<size_t> MaxSubPatterns) {
}

Expected<GlobPattern::SubGlobPattern>
GlobPattern::SubGlobPattern::create(StringRef S) {
GlobPattern::SubGlobPattern::create(StringRef S, bool SlashAgnostic) {
SubGlobPattern Pat;
Pat.IsSlashAgnostic = SlashAgnostic;

// Parse brackets.
Pat.Pat.assign(S.begin(), S.end());
Expand Down Expand Up @@ -231,6 +233,10 @@ bool GlobPattern::SubGlobPattern::match(StringRef Str) const {
++S;
continue;
}
} else if (IsSlashAgnostic && *P == '/' && (*S == '/' || *S == '\\')) {
++P;
++S;
continue;
} else if (*P == *S || *P == '?') {
++P;
++S;
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Support/SpecialCaseList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber,
Glob->LineNo = LineNumber;
// We must be sure to use the string in `Glob` rather than the provided
// reference which could be destroyed before match() is called
if (auto Err = GlobPattern::create(Glob->Name, /*MaxSubPatterns=*/1024)
if (auto Err = GlobPattern::create(Glob->Name, /*MaxSubPatterns=*/1024,
/*IsSlashAgnostic=*/true)
.moveInto(Glob->Pattern))
return Err;
Globs.push_back(std::move(Glob));
Expand Down