diff options
| author | Qinkun Bao <qinkun@google.com> | 2025-05-27 17:32:30 +0000 |
|---|---|---|
| committer | Qinkun Bao <qinkun@google.com> | 2025-05-27 17:32:30 +0000 |
| commit | d858fbe3ce415fda7d43d4e99c5a94646174b965 (patch) | |
| tree | ed2979d1141fe0e44ec1973d958078895bc921f0 | |
| parent | d5802c30ae6cf296489daf12b36582e9e1d658bb (diff) | |
[𝘀𝗽𝗿] changes to main this commit is based onusers/qinkunbao/spr/main.ubsan-support-srcsanitize-for-multiple-ignorelists
Created using spr 1.3.6
[skip ci]
| -rw-r--r-- | clang/docs/ReleaseNotes.rst | 1 | ||||
| -rw-r--r-- | clang/docs/SanitizerSpecialCaseList.rst | 26 | ||||
| -rw-r--r-- | clang/include/clang/Basic/SanitizerSpecialCaseList.h | 7 | ||||
| -rw-r--r-- | clang/lib/Basic/NoSanitizeList.cpp | 10 | ||||
| -rw-r--r-- | clang/lib/Basic/SanitizerSpecialCaseList.cpp | 21 | ||||
| -rw-r--r-- | clang/test/CodeGen/ubsan-src-ignorelist-category.test | 36 | ||||
| -rw-r--r-- | llvm/include/llvm/Support/SpecialCaseList.h | 15 | ||||
| -rw-r--r-- | llvm/lib/Support/SpecialCaseList.cpp | 34 | ||||
| -rw-r--r-- | llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp | 15 | ||||
| -rw-r--r-- | llvm/unittests/Support/SpecialCaseListTest.cpp | 62 |
10 files changed, 176 insertions, 51 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b93fa33acc2a..80a5b7072677 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1009,6 +1009,7 @@ Sanitizers ---------- - ``-fsanitize=vptr`` is no longer a part of ``-fsanitize=undefined``. +- Sanitizer ignorelists now support the syntax ``src:*=sanitize``. Python Binding Changes ---------------------- diff --git a/clang/docs/SanitizerSpecialCaseList.rst b/clang/docs/SanitizerSpecialCaseList.rst index 5c88c2976e86..692af8df0359 100644 --- a/clang/docs/SanitizerSpecialCaseList.rst +++ b/clang/docs/SanitizerSpecialCaseList.rst @@ -58,7 +58,7 @@ Usage with UndefinedBehaviorSanitizer ability to adjust instrumentation based on type. By default, supported sanitizers will have their instrumentation disabled for -types specified within an ignorelist. +entries specified within an ignorelist. .. code-block:: bash @@ -77,10 +77,9 @@ For example, supplying the above ``ignorelist.txt`` to ``-fsanitize-ignorelist=ignorelist.txt`` disables overflow sanitizer instrumentation for arithmetic operations containing values of type ``int``. -The ``=sanitize`` category is also supported. Any types assigned to the -``sanitize`` category will have their sanitizer instrumentation remain. If the -same type appears within or across ignorelists with different categories the -``sanitize`` category takes precedence -- regardless of order. +The ``=sanitize`` category is also supported. Any ``=sanitize`` category +entries enable sanitizer instrumentation, even if it was ignored by entries +before. With this, one may disable instrumentation for some or all types and specifically allow instrumentation for one or many types -- including types @@ -103,6 +102,23 @@ supported sanitizers. char c = toobig; // also not instrumented } +If multiple entries match the source, than the latest entry takes the +precedence. + +.. code-block:: bash + + $ cat ignorelist1.txt + # test.cc will be instrumented. + src:* + src:*/mylib/*=sanitize + src:*/mylib/test.cc + + $ cat ignorelist2.txt + # test.cc will not be instrumented. + src:* + src:*/mylib/test.cc + src:*/mylib/*=sanitize + Format ====== diff --git a/clang/include/clang/Basic/SanitizerSpecialCaseList.h b/clang/include/clang/Basic/SanitizerSpecialCaseList.h index d024b7dfc2e8..25d518e7128c 100644 --- a/clang/include/clang/Basic/SanitizerSpecialCaseList.h +++ b/clang/include/clang/Basic/SanitizerSpecialCaseList.h @@ -43,13 +43,18 @@ public: bool inSection(SanitizerMask Mask, StringRef Prefix, StringRef Query, StringRef Category = StringRef()) const; + // Query ignorelisted entries if any bit in Mask matches the entry's section. + // Return 0 if not found. If found, return the line number (starts with 1). + unsigned inSectionBlame(SanitizerMask Mask, StringRef Prefix, StringRef Query, + StringRef Category = StringRef()) const; + protected: // Initialize SanitizerSections. void createSanitizerSections(); struct SanitizerSection { SanitizerSection(SanitizerMask SM, SectionEntries &E) - : Mask(SM), Entries(E){}; + : Mask(SM), Entries(E) {}; SanitizerMask Mask; SectionEntries &Entries; diff --git a/clang/lib/Basic/NoSanitizeList.cpp b/clang/lib/Basic/NoSanitizeList.cpp index e7e63c1f419e..4feef5c6ea05 100644 --- a/clang/lib/Basic/NoSanitizeList.cpp +++ b/clang/lib/Basic/NoSanitizeList.cpp @@ -44,7 +44,15 @@ bool NoSanitizeList::containsFunction(SanitizerMask Mask, bool NoSanitizeList::containsFile(SanitizerMask Mask, StringRef FileName, StringRef Category) const { - return SSCL->inSection(Mask, "src", FileName, Category); + unsigned NoSanLine = SSCL->inSectionBlame(Mask, "src", FileName, Category); + if (NoSanLine == 0) + return false; + unsigned SanLine = SSCL->inSectionBlame(Mask, "src", FileName, "sanitize"); + // If we have two cases such as `src:a.cpp=sanitize` and `src:a.cpp`, the + // current entry override the previous entry. + if (SanLine > 0) + return NoSanLine > SanLine; + return true; } bool NoSanitizeList::containsMainFile(SanitizerMask Mask, StringRef FileName, diff --git a/clang/lib/Basic/SanitizerSpecialCaseList.cpp b/clang/lib/Basic/SanitizerSpecialCaseList.cpp index 2dbf04c6ede9..4508d705eb43 100644 --- a/clang/lib/Basic/SanitizerSpecialCaseList.cpp +++ b/clang/lib/Basic/SanitizerSpecialCaseList.cpp @@ -56,10 +56,21 @@ void SanitizerSpecialCaseList::createSanitizerSections() { bool SanitizerSpecialCaseList::inSection(SanitizerMask Mask, StringRef Prefix, StringRef Query, StringRef Category) const { - for (auto &S : SanitizerSections) - if ((S.Mask & Mask) && - SpecialCaseList::inSectionBlame(S.Entries, Prefix, Query, Category)) - return true; + return inSectionBlame(Mask, Prefix, Query, Category); +} - return false; +unsigned SanitizerSpecialCaseList::inSectionBlame(SanitizerMask Mask, + StringRef Prefix, + StringRef Query, + StringRef Category) const { + for (auto it = SanitizerSections.crbegin(); it != SanitizerSections.crend(); + ++it) { + if (it->Mask & Mask) { + unsigned lineNum = + SpecialCaseList::inSectionBlame(it->Entries, Prefix, Query, Category); + if (lineNum > 0) + return lineNum; + } + } + return 0; } diff --git a/clang/test/CodeGen/ubsan-src-ignorelist-category.test b/clang/test/CodeGen/ubsan-src-ignorelist-category.test index 2f196fb126fe..55967ec77c83 100644 --- a/clang/test/CodeGen/ubsan-src-ignorelist-category.test +++ b/clang/test/CodeGen/ubsan-src-ignorelist-category.test @@ -3,14 +3,15 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist -emit-llvm %t/test2.c -o - | FileCheck %s --check-prefixes=CHECK2 -// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,SANITIZE // RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict1 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE -// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict2 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict2 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,SANITIZE // RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict3 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE -// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict4 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict4 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,SANITIZE // RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict5 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE -// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict6 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE - +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict6 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,SANITIZE +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict7 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,IGNORE +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignorelist=%t/src.ignorelist.contradict8 -emit-llvm %t/test1.c -o - | FileCheck %s --check-prefixes=CHECK1,SANITIZE // Verify ubsan only emits checks for files in the allowlist @@ -52,6 +53,31 @@ src:*/tes*1.c=sanitize src:*/te*t1.c src:*/t*st1.c=sanitize +//--- src.ignorelist.contradict7 +[{unsigned-integer-overflow,signed-integer-overflow}] +src:* +src:*/tes*1.c=sanitize +src:*/te*t1.c +src:*/t*st1.c=sanitize +[{unsigned-integer-overflow,signed-integer-overflow}] +src:* +src:*/te*t1.c +src:*/tes*1.c=sanitize +src:*/test1.c + +//--- src.ignorelist.contradict8 +[{unsigned-integer-overflow,signed-integer-overflow}] +src:* +src:*/te*t1.c +src:*/tes*1.c=sanitize +src:*/test1.c +[{unsigned-integer-overflow,signed-integer-overflow}] +src:* +src:*/tes*1.c=sanitize +src:*/te*t1.c +src:*/t*st1.c=sanitize + + //--- test1.c // CHECK1-LABEL: define dso_local i32 @add int add(int a, int b) { diff --git a/llvm/include/llvm/Support/SpecialCaseList.h b/llvm/include/llvm/Support/SpecialCaseList.h index 653a3b14ebf0..d54b242a9c50 100644 --- a/llvm/include/llvm/Support/SpecialCaseList.h +++ b/llvm/include/llvm/Support/SpecialCaseList.h @@ -18,6 +18,7 @@ #include "llvm/Support/Regex.h" #include <memory> #include <string> +#include <utility> #include <vector> namespace llvm { @@ -93,17 +94,17 @@ public: LLVM_ABI bool inSection(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 contains a line + /// Returns the file index and the line numebr <FileIdx, LineNo> corresponding + /// to the special case list entry if the special case list contains a line /// \code /// @Prefix:<E>=@Category /// \endcode /// where @Query satisfies the glob <E> in a given @Section. - /// Returns zero if there is no exclusion entry corresponding to this + /// Returns (zero, zero) if there is no exclusion entry corresponding to this /// expression. - LLVM_ABI unsigned inSectionBlame(StringRef Section, StringRef Prefix, - StringRef Query, - StringRef Category = StringRef()) const; + LLVM_ABI std::pair<unsigned, unsigned> + inSectionBlame(StringRef Section, StringRef Prefix, StringRef Query, + StringRef Category = StringRef()) const; protected: // Implementations of the create*() functions that can also be used by derived @@ -145,12 +146,14 @@ protected: Section(std::unique_ptr<Matcher> M) : SectionMatcher(std::move(M)) {}; Section() : Section(std::make_unique<Matcher>()) {}; + unsigned FileIdx; std::unique_ptr<Matcher> SectionMatcher; SectionEntries Entries; std::string SectionStr; }; std::vector<Section> Sections; + unsigned currFileIdx; LLVM_ABI Expected<Section *> addSection(StringRef SectionStr, unsigned LineNo, bool UseGlobs = true); diff --git a/llvm/lib/Support/SpecialCaseList.cpp b/llvm/lib/Support/SpecialCaseList.cpp index 47ff3e24706a..5a66f163d791 100644 --- a/llvm/lib/Support/SpecialCaseList.cpp +++ b/llvm/lib/Support/SpecialCaseList.cpp @@ -66,12 +66,12 @@ Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber, } unsigned SpecialCaseList::Matcher::match(StringRef Query) const { - for (const auto &Glob : Globs) - if (Glob->Pattern.match(Query)) - return Glob->LineNo; - for (const auto &[Regex, LineNumber] : RegExes) - if (Regex->match(Query)) - return LineNumber; + for (auto it = Globs.crbegin(); it != Globs.crend(); ++it) + if ((*it)->Pattern.match(Query)) + return (*it)->LineNo; + for (auto it = RegExes.crbegin(); it != RegExes.crend(); ++it) + if (it->first->match(Query)) + return it->second; return 0; } @@ -112,6 +112,7 @@ bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths, return false; } std::string ParseError; + ++currFileIdx; if (!parse(FileOrErr.get().get(), ParseError)) { Error = (Twine("error parsing file '") + Path + "': " + ParseError).str(); return false; @@ -122,6 +123,7 @@ bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths, bool SpecialCaseList::createInternal(const MemoryBuffer *MB, std::string &Error) { + ++currFileIdx; if (!parse(MB, Error)) return false; return true; @@ -133,6 +135,7 @@ SpecialCaseList::addSection(StringRef SectionStr, unsigned LineNo, Sections.emplace_back(); auto &Section = Sections.back(); Section.SectionStr = SectionStr; + Section.FileIdx = currFileIdx; if (auto Err = Section.SectionMatcher->insert(SectionStr, LineNo, UseGlobs)) { return createStringError(errc::invalid_argument, @@ -207,20 +210,21 @@ SpecialCaseList::~SpecialCaseList() = default; bool SpecialCaseList::inSection(StringRef Section, StringRef Prefix, StringRef Query, StringRef Category) const { - return inSectionBlame(Section, Prefix, Query, Category); + auto [FileIdx, LineNo] = inSectionBlame(Section, Prefix, Query, Category); + return LineNo; } -unsigned SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix, - StringRef Query, - StringRef Category) const { - for (const auto &S : Sections) { - if (S.SectionMatcher->match(Section)) { - unsigned Blame = inSectionBlame(S.Entries, Prefix, Query, Category); +std::pair<unsigned, unsigned> +SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix, + StringRef Query, StringRef Category) const { + for (auto it = Sections.crbegin(); it != Sections.crend(); ++it) { + if (it->SectionMatcher->match(Section)) { + unsigned Blame = inSectionBlame(it->Entries, Prefix, Query, Category); if (Blame) - return Blame; + return {it->FileIdx, Blame}; } } - return 0; + return {0, 0}; } unsigned SpecialCaseList::inSectionBlame(const SectionEntries &Entries, diff --git a/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp b/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp index 0f2c7da94230..b37295720469 100644 --- a/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp +++ b/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp @@ -78,8 +78,7 @@ static void printBlameContext(const DILineInfo &LineInfo, unsigned Context) { File->getBuffer().split(Lines, '\n'); for (unsigned i = std::max<size_t>(1, LineInfo.Line - Context); - i < - std::min<size_t>(Lines.size() + 1, LineInfo.Line + Context + 1); + i < std::min<size_t>(Lines.size() + 1, LineInfo.Line + Context + 1); ++i) { if (i == LineInfo.Line) outs() << ">"; @@ -193,12 +192,16 @@ printIndirectCFInstructions(FileAnalysis &Analysis, unsigned BlameLine = 0; for (auto &K : {"cfi-icall", "cfi-vcall"}) { - if (!BlameLine) - BlameLine = + if (!BlameLine) { + auto [FileIdx, Line] = SpecialCaseList->inSectionBlame(K, "src", LineInfo.FileName); - if (!BlameLine) - BlameLine = + BlameLine = Line; + } + if (!BlameLine) { + auto [FileIdx, Line] = SpecialCaseList->inSectionBlame(K, "fun", LineInfo.FunctionName); + BlameLine = Line; + } } if (BlameLine) { diff --git a/llvm/unittests/Support/SpecialCaseListTest.cpp b/llvm/unittests/Support/SpecialCaseListTest.cpp index 4289a5e70215..0fe6a427c056 100644 --- a/llvm/unittests/Support/SpecialCaseListTest.cpp +++ b/llvm/unittests/Support/SpecialCaseListTest.cpp @@ -14,6 +14,7 @@ #include "gtest/gtest.h" using testing::HasSubstr; +using testing::Pair; using testing::StartsWith; using namespace llvm; @@ -70,13 +71,14 @@ TEST_F(SpecialCaseListTest, Basic) { EXPECT_FALSE(SCL->inSection("", "fun", "hello")); EXPECT_FALSE(SCL->inSection("", "src", "hello", "category")); - EXPECT_EQ(3u, SCL->inSectionBlame("", "src", "hello")); - EXPECT_EQ(4u, SCL->inSectionBlame("", "src", "bye")); - EXPECT_EQ(5u, SCL->inSectionBlame("", "src", "hi", "category")); - EXPECT_EQ(6u, SCL->inSectionBlame("", "src", "zzzz", "category")); - EXPECT_EQ(0u, SCL->inSectionBlame("", "src", "hi")); - EXPECT_EQ(0u, SCL->inSectionBlame("", "fun", "hello")); - EXPECT_EQ(0u, SCL->inSectionBlame("", "src", "hello", "category")); + EXPECT_THAT(SCL->inSectionBlame("", "src", "hello"), Pair(1u, 3u)); + EXPECT_THAT(SCL->inSectionBlame("", "src", "bye"), Pair(1u, 4u)); + EXPECT_THAT(SCL->inSectionBlame("", "src", "hi", "category"), Pair(1u, 5u)); + EXPECT_THAT(SCL->inSectionBlame("", "src", "zzzz", "category"), Pair(1u, 6u)); + EXPECT_THAT(SCL->inSectionBlame("", "src", "hi"), Pair(0u, 0u)); + EXPECT_THAT(SCL->inSectionBlame("", "fun", "hello"), Pair(0u, 0u)); + EXPECT_THAT(SCL->inSectionBlame("", "src", "hello", "category"), + Pair(0u, 0u)); } TEST_F(SpecialCaseListTest, CorrectErrorLineNumberWithBlankLine) { @@ -306,4 +308,50 @@ TEST_F(SpecialCaseListTest, Version2) { EXPECT_TRUE(SCL->inSection("sect2", "fun", "bar")); EXPECT_FALSE(SCL->inSection("sect3", "fun", "bar")); } + +TEST_F(SpecialCaseListTest, Version3) { + std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("[sect1]\n" + "src:foo*\n" + "[sect1]\n" + "src:bar*\n" + "src:def\n" + "[sect2]\n" + "src:def\n" + "src:de*\n"); + EXPECT_TRUE(SCL->inSection("sect1", "src", "fooz")); + EXPECT_TRUE(SCL->inSection("sect1", "src", "barz")); + EXPECT_FALSE(SCL->inSection("sect2", "src", "fooz")); + + EXPECT_TRUE(SCL->inSection("sect2", "src", "def")); + EXPECT_TRUE(SCL->inSection("sect1", "src", "def")); + + EXPECT_THAT(SCL->inSectionBlame("sect1", "src", "fooz"), Pair(1u, 2u)); + EXPECT_THAT(SCL->inSectionBlame("sect1", "src", "barz"), Pair(1u, 4u)); + EXPECT_THAT(SCL->inSectionBlame("sect1", "src", "def"), Pair(1u, 5u)); + EXPECT_THAT(SCL->inSectionBlame("sect2", "src", "def"), Pair(1u, 8u)); + EXPECT_THAT(SCL->inSectionBlame("sect2", "src", "dez"), Pair(1u, 8u)); } + +TEST_F(SpecialCaseListTest, FileIdx) { + std::vector<std::string> Files; + Files.push_back(makeSpecialCaseListFile("src:bar\n" + "src:*foo*\n" + "src:ban=init\n" + "src:baz\n" + "src:*def\n")); + Files.push_back(makeSpecialCaseListFile("src:baz\n" + "src:car\n" + "src:def*")); + auto SCL = SpecialCaseList::createOrDie(Files, *vfs::getRealFileSystem()); + EXPECT_THAT(SCL->inSectionBlame("", "src", "bar"), Pair(1u, 1u)); + EXPECT_THAT(SCL->inSectionBlame("", "src", "fooaaaaaa"), Pair(1u, 2u)); + EXPECT_THAT(SCL->inSectionBlame("", "src", "ban", "init"), Pair(1u, 3u)); + EXPECT_THAT(SCL->inSectionBlame("", "src", "baz"), Pair(2u, 1u)); + EXPECT_THAT(SCL->inSectionBlame("", "src", "car"), Pair(2u, 2u)); + EXPECT_THAT(SCL->inSectionBlame("", "src", "aaaadef"), Pair(1u, 5u)); + EXPECT_THAT(SCL->inSectionBlame("", "src", "defaaaaa"), Pair(2u, 3u)); + for (auto &Path : Files) + sys::fs::remove(Path); +} + +} // namespace |
