diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 35ab1461e7b89..ee74431cf33a7 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1013,6 +1013,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 5c88c2976e861..692af8df0359b 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 d024b7dfc2e85..25d518e7128cf 100644 --- a/clang/include/clang/Basic/SanitizerSpecialCaseList.h +++ b/clang/include/clang/Basic/SanitizerSpecialCaseList.h @@ -43,13 +43,18 @@ class SanitizerSpecialCaseList : public llvm::SpecialCaseList { 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 e7e63c1f419e6..97e2acc2116b1 100644 --- a/clang/lib/Basic/NoSanitizeList.cpp +++ b/clang/lib/Basic/NoSanitizeList.cpp @@ -44,7 +44,13 @@ 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. + return !SanLine || NoSanLine > SanLine; } bool NoSanitizeList::containsMainFile(SanitizerMask Mask, StringRef FileName, diff --git a/clang/lib/Basic/SanitizerSpecialCaseList.cpp b/clang/lib/Basic/SanitizerSpecialCaseList.cpp index 2dbf04c6ede97..bb68763b817e6 100644 --- a/clang/lib/Basic/SanitizerSpecialCaseList.cpp +++ b/clang/lib/Basic/SanitizerSpecialCaseList.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// #include "clang/Basic/SanitizerSpecialCaseList.h" +#include "llvm/ADT/STLExtras.h" using namespace clang; @@ -56,10 +57,20 @@ 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 (const auto &S : llvm::reverse(SanitizerSections)) { + if (S.Mask & Mask) { + unsigned lineNum = + SpecialCaseList::inSectionBlame(S.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 2f196fb126fe7..55967ec77c836 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) {