[clang] [Clang] Implement labelled type filtering for overflow/truncation sanitizers w/ SSCLs (PR #107332)

Justin Stitt via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 30 11:00:38 PDT 2024


https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/107332

>From 548efc6414503f8ae005f1bd9ef2c7f15ad16241 Mon Sep 17 00:00:00 2001
From: Justin Stitt <justinstitt at google.com>
Date: Tue, 3 Sep 2024 18:28:53 -0700
Subject: [PATCH 1/6] hook up sscl categories with overflow/truncation
 sanitizers

Signed-off-by: Justin Stitt <justinstitt at google.com>
---
 clang/include/clang/AST/ASTContext.h         |  3 +
 clang/lib/AST/ASTContext.cpp                 | 31 +++++++
 clang/lib/CodeGen/CGExprScalar.cpp           | 36 +++++++-
 clang/test/CodeGen/ubsan-type-ignorelist.cpp | 88 +++++++++++++++++---
 4 files changed, 144 insertions(+), 14 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 1984310df0442e..44878d74499f66 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -830,6 +830,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
 
   const NoSanitizeList &getNoSanitizeList() const { return *NoSanitizeL; }
 
+  bool isTypeIgnoredBySanitizer(const SanitizerMask &Mask,
+                                const QualType &Ty) const;
+
   const XRayFunctionFilter &getXRayFilter() const {
     return *XRayFilter;
   }
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index fd8aa8de79b49f..4270ddc90b7b24 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -831,6 +831,37 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
   return CanonTTP;
 }
 
+/// Check if a type can have its sanitizer instrumentation elided.
+/// Determine this by its presence in a SCL alongside its specified categories.
+/// For example:
+/// ignorelist.txt>
+/// [{unsigned-integer-overflow,signed-integer-overflow}]
+/// type:*
+/// type:size_t=skip
+/// <ignorelist.txt
+/// Supplying the above ignorelist.txt will disable overflow sanitizer
+/// instrumentation for all types except "size_t".
+bool ASTContext::isTypeIgnoredBySanitizer(const SanitizerMask &Mask,
+                                          const QualType &Ty) const {
+  // One may specifically allow a type "type:foo=allow"
+  bool isAllowedBySCL =
+      NoSanitizeL->containsType(Mask, Ty.getAsString(), "allow");
+
+  // There could also be no category present "type:foo", which is the same as
+  // "allow"
+  isAllowedBySCL |= NoSanitizeL->containsType(Mask, Ty.getAsString());
+
+  // Explicitly specifying "skip" is also possible "type:foo=skip"
+  bool isSkippedBySCL =
+      NoSanitizeL->containsType(Mask, Ty.getAsString(), "skip");
+
+  // Or "forbid", as there is currently no distinction between "skip" and
+  // "forbid" for the purposes of the overflow/truncation sanitizer ignorelist.
+  isSkippedBySCL |= NoSanitizeL->containsType(Mask, Ty.getAsString(), "forbid");
+
+  return isAllowedBySCL && !isSkippedBySCL;
+}
+
 TargetCXXABI::Kind ASTContext::getCXXABIKind() const {
   auto Kind = getTargetInfo().getCXXABI().getKind();
   return getLangOpts().CXXABI.value_or(Kind);
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index b7f5b932c56b6f..bc19813a04e42f 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -197,6 +197,18 @@ static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) {
   if (!Op.mayHaveIntegerOverflow())
     return true;
 
+  if (Op.Ty->isSignedIntegerType() &&
+      Ctx.isTypeIgnoredBySanitizer(SanitizerKind::SignedIntegerOverflow,
+                                   Op.Ty)) {
+    return true;
+  }
+
+  if (Op.Ty->isUnsignedIntegerType() &&
+      Ctx.isTypeIgnoredBySanitizer(SanitizerKind::UnsignedIntegerOverflow,
+                                   Op.Ty)) {
+    return true;
+  }
+
   const UnaryOperator *UO = dyn_cast<UnaryOperator>(Op.E);
 
   if (UO && UO->getOpcode() == UO_Minus &&
@@ -1121,6 +1133,10 @@ void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType,
   if (!CGF.SanOpts.has(Check.second.second))
     return;
 
+  // Does some SSCL ignore this type?
+  if (CGF.getContext().isTypeIgnoredBySanitizer(Check.second.second, DstType))
+    return;
+
   llvm::Constant *StaticArgs[] = {
       CGF.EmitCheckSourceLocation(Loc), CGF.EmitCheckTypeDescriptor(SrcType),
       CGF.EmitCheckTypeDescriptor(DstType),
@@ -1231,6 +1247,15 @@ void ScalarExprEmitter::EmitIntegerSignChangeCheck(Value *Src, QualType SrcType,
     // Because here sign change check is interchangeable with truncation check.
     return;
   }
+  // Does an SSCL have an entry for the DstType under its respective sanitizer
+  // section?
+  if (DstSigned && CGF.getContext().isTypeIgnoredBySanitizer(
+                       SanitizerKind::ImplicitSignedIntegerTruncation, DstType))
+    return;
+  if (!DstSigned &&
+      CGF.getContext().isTypeIgnoredBySanitizer(
+          SanitizerKind::ImplicitUnsignedIntegerTruncation, DstType))
+    return;
   // That's it. We can't rule out any more cases with the data we have.
 
   CodeGenFunction::SanitizerScope SanScope(&CGF);
@@ -2780,10 +2805,11 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior(
       return Builder.CreateNSWAdd(InVal, Amount, Name);
     [[fallthrough]];
   case LangOptions::SOB_Trapping:
-    if (!E->canOverflow())
+    BinOpInfo Info = createBinOpInfoFromIncDec(
+        E, InVal, IsInc, E->getFPFeaturesInEffect(CGF.getLangOpts()));
+    if (!E->canOverflow() || CanElideOverflowCheck(CGF.getContext(), Info))
       return Builder.CreateNSWAdd(InVal, Amount, Name);
-    return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(
-        E, InVal, IsInc, E->getFPFeaturesInEffect(CGF.getLangOpts())));
+    return EmitOverflowCheckedBinOp(Info);
   }
   llvm_unreachable("Unknown SignedOverflowBehaviorTy");
 }
@@ -2986,7 +3012,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
       value = EmitIncDecConsiderOverflowBehavior(E, value, isInc);
     } else if (E->canOverflow() && type->isUnsignedIntegerType() &&
                CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
-               !excludeOverflowPattern) {
+               !excludeOverflowPattern &&
+               !CGF.getContext().isTypeIgnoredBySanitizer(
+                   SanitizerKind::UnsignedIntegerOverflow, E->getType())) {
       value = EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(
           E, value, isInc, E->getFPFeaturesInEffect(CGF.getLangOpts())));
     } else {
diff --git a/clang/test/CodeGen/ubsan-type-ignorelist.cpp b/clang/test/CodeGen/ubsan-type-ignorelist.cpp
index 7bea84f5fabb93..2364b692e53160 100644
--- a/clang/test/CodeGen/ubsan-type-ignorelist.cpp
+++ b/clang/test/CodeGen/ubsan-type-ignorelist.cpp
@@ -1,23 +1,91 @@
+// Verify ubsan doesn't emit checks for ignorelisted types
+// RUN: echo "[{unsigned-integer-overflow,signed-integer-overflow}]" > %t-int.ignorelist
+// RUN: echo "type:int" >> %t-int.ignorelist
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t-int.ignorelist -emit-llvm %s -o - | FileCheck %s --check-prefix=INT
+
+// RUN: echo "type:int" > %t-nosection.ignorelist
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t-nosection.ignorelist -emit-llvm %s -o - | FileCheck %s --check-prefix=INT
+
+// RUN: echo "type:int=allow" > %t-allow-same-as-no-category.ignorelist
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t-allow-same-as-no-category.ignorelist -emit-llvm %s -o - | FileCheck %s --check-prefix=INT
+
+// RUN: echo "[{unsigned-integer-overflow,signed-integer-overflow}]" > %t-myty.ignorelist
+// RUN: echo "type:*" >> %t-myty.ignorelist
+// RUN: echo "type:myty=skip" >> %t-myty.ignorelist
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t-myty.ignorelist -emit-llvm %s -o - | FileCheck %s --check-prefix=MYTY
+
+// RUN: echo "[{implicit-signed-integer-truncation,implicit-unsigned-integer-truncation}]" > %t-trunc.ignorelist
+// RUN: echo "type:char" >> %t-trunc.ignorelist
+// RUN: echo "type:unsigned char" >> %t-trunc.ignorelist
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=implicit-signed-integer-truncation,implicit-unsigned-integer-truncation -fsanitize-ignorelist=%t-trunc.ignorelist -emit-llvm %s -o - | FileCheck %s --check-prefix=TRUNC
+
 // Verify ubsan vptr does not check down-casts on ignorelisted types.
 // RUN: echo "type:_ZTI3Foo" > %t-type.ignorelist
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=vptr -fsanitize-recover=vptr -emit-llvm %s -o - | FileCheck %s --check-prefix=DEFAULT
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=vptr -fsanitize-recover=vptr -fsanitize-ignorelist=%t-type.ignorelist -emit-llvm %s -o - | FileCheck %s --check-prefix=TYPE
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=vptr -fsanitize-recover=vptr -emit-llvm %s -o - | FileCheck %s --check-prefix=VPTR
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=vptr -fsanitize-recover=vptr -fsanitize-ignorelist=%t-type.ignorelist -emit-llvm %s -o - | FileCheck %s --check-prefix=VPTR-TYPE
 
 class Bar {
-public:
-  virtual ~Bar() {}
+  public:
+    virtual ~Bar() {}
 };
 class Foo : public Bar {};
 
 Bar bar;
 
-// DEFAULT: @_Z7checkmev
-// TYPE: @_Z7checkmev
+// VPTR: @_Z7checkmev
+// VPTR-TYPE: @_Z7checkmev
 void checkme() {
-// DEFAULT: call void @__ubsan_handle_dynamic_type_cache_miss({{.*}} (ptr @bar to
-// TYPE-NOT: @__ubsan_handle_dynamic_type_cache_miss
+  // VPTR: call void @__ubsan_handle_dynamic_type_cache_miss({{.*}} (ptr @bar to
+  // VPTR-TYPE-NOT: @__ubsan_handle_dynamic_type_cache_miss
   Foo* foo = static_cast<Foo*>(&bar); // down-casting
-// DEFAULT: ret void
-// TYPE: ret void
+                                      // VPTR: ret void
+                                      // VPTR-TYPE: ret void
   return;
 }
+
+// INT-LABEL: ignore_int
+void ignore_int(int A, int B, unsigned C, unsigned D, long E) {
+  // INT: llvm.uadd.with.overflow.i32
+  (void)(C+D);
+  // INT-NOT: llvm.sadd.with.overflow.i32
+  (void)(A+B);
+  // INT: llvm.sadd.with.overflow.i64
+  (void)(++E);
+}
+
+
+typedef unsigned long myty;
+typedef myty derivative;
+// INT-LABEL: ignore_all_except_myty
+// MYTY-LABEL: ignore_all_except_myty
+void ignore_all_except_myty(myty A, myty B, int C, unsigned D, derivative E) {
+  // MYTY-NOT: llvm.sadd.with.overflow.i32
+  (void)(++C);
+
+  // MYTY-NOT: llvm.uadd.with.overflow.i32
+  (void)(D+D);
+
+  // MYTY-NOT: llvm.umul.with.overflow.i64
+  (void)(E*2);
+
+  // MYTY: llvm.uadd.with.overflow.i64
+  (void)(A+B);
+}
+
+// INT-LABEL: truncation
+// MYTY-LABEL: truncation
+// TRUNC-LABEL: truncation
+void truncation(char A, int B, unsigned char C, short D) {
+  // TRUNC-NOT: %handler.implicit_conversion
+  A = B;
+  // TRUNC-NOT: %handler.implicit_conversion
+  A = C;
+  // TRUNC-NOT: %handler.implicit_conversion
+  C = B;
+
+  // TRUNC: %handler.implicit_conversion
+  D = B;
+
+  (void)A;
+  (void)D;
+}

>From 6efbd7b17ca247ddeef1a261c3813df6516bac23 Mon Sep 17 00:00:00 2001
From: Justin Stitt <justinstitt at google.com>
Date: Wed, 4 Sep 2024 15:43:21 -0700
Subject: [PATCH 2/6] add docs

Signed-off-by: Justin Stitt <justinstitt at google.com>
---
 clang/docs/ReleaseNotes.rst             |  8 ++++
 clang/docs/SanitizerSpecialCaseList.rst | 62 ++++++++++++++++++++++++-
 2 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 14907e7db18de3..1051dde3b7ef47 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -635,6 +635,14 @@ Sanitizers
   This new flag should allow those projects to enable integer sanitizers with
   less noise.
 
+- Arithmetic overflow sanitizers ``-fsanitize=signed-integer-overflow`` and
+  ``-fsanitize=unsigned-integer-overflow`` as well as the implicit integer
+  truncation sanitizers ``-fsanitize=implicit-signed-integer-truncation`` and
+  ``-fsanitize=implicit-unsigned-integer-truncation`` now properly support the
+  "type" prefix within `Sanitizer Special Case Lists (SSCL)
+  <https://clang.llvm.org/docs/SanitizerSpecialCaseList.html>`_. See that link
+  for examples.
+
 Python Binding Changes
 ----------------------
 - Fixed an issue that led to crashes when calling ``Type.get_exception_specification_kind``.
diff --git a/clang/docs/SanitizerSpecialCaseList.rst b/clang/docs/SanitizerSpecialCaseList.rst
index c7fb0fa3f8a828..13f71b878d4cc8 100644
--- a/clang/docs/SanitizerSpecialCaseList.rst
+++ b/clang/docs/SanitizerSpecialCaseList.rst
@@ -15,8 +15,9 @@ file at compile-time.
 Goal and usage
 ==============
 
-Users of sanitizer tools, such as :doc:`AddressSanitizer`, :doc:`ThreadSanitizer`
-or :doc:`MemorySanitizer` may want to disable or alter some checks for
+Users of sanitizer tools, such as :doc:`AddressSanitizer`,
+:doc:`ThreadSanitizer`, :doc:`MemorySanitizer` or :doc:
+`UndefinedBehaviorSanitizer` may want to disable or alter some checks for
 certain source-level entities to:
 
 * speedup hot function, which is known to be correct;
@@ -48,6 +49,63 @@ Example
   $ clang -fsanitize=address -fsanitize-ignorelist=ignorelist.txt foo.c ; ./a.out
   # No error report here.
 
+Usage with UndefinedBehaviorSanitizer
+=====================================
+
+The arithmetic overflow sanitizers ``unsigned-integer-overflow`` and
+``signed-integer-overflow`` as well as the implicit integer truncation
+sanitizers ``implicit-signed-integer-truncation`` and
+``implicit-unsigned-integer-truncation`` support the ability to adjust
+instrumentation based on type.
+
+.. code-block:: bash
+
+  $ cat foo.c
+  void foo() {
+    int a = 2147483647; // INT_MAX
+    ++a;                // Normally, an overflow with -fsanitize=signed-integer-overflow
+  }
+  $ cat ignorelist.txt
+  [signed-integer-overflow]
+  type:int
+  $ clang -fsanitize=signed-integer-overflow -fsanitize-ignorelist=ignorelist.txt foo.c ; ./a.out
+  # no signed-integer-overflow error
+
+Supplying ``ignorelist.txt`` with ``-fsanitize-ignorelist=ignorelist.txt``
+disables overflow sanitizer instrumentation for arithmetic operations
+containing values of type ``int``, for example. Custom types may be used.
+
+The following SCL categories are supported: ``=allow``, ``=skip`` and
+``=forbid``. The ``allow`` category is the default for any entry and specifies
+that the query, if matched, will have its sanitizer instrumentation ignored.
+Conversely, both ``skip`` and ``forbid`` cause their queries, if matched, to be
+left out of the ignorelist -- essentially ensuring sanitizer instrumentation
+remains for those types. This is useful for whitelisting specific types.
+
+With this, one may disable instrumentation for all types and specifically allow
+instrumentation for one or many types.
+
+.. code-block:: bash
+
+  $ cat ignorelist.txt
+  [implicit-signed-integer-truncation]
+  type:*=allow
+  type:T=skip
+  $ cat foo.c
+  typedef char T;
+  typedef char U;
+  void foo(int toobig) {
+    T a = toobig;    // instrumented
+    U b = toobig;    // not instrumented
+    char c = toobig; // also not instrumented
+  }
+
+Note that ``skip`` and ``forbid`` operate exactly the same in this context and
+both options exist simply for conformity with the `-fprofile-list
+<https://clang.llvm.org/docs/UsersManual.html#instrumenting-only-selected-files-or-functions>`_
+syntax for adjusting profile instrumentation. You do not need to specify any
+`default:<type>` for ``-fsanitize-ignorelist`` SSCLs, though.
+
 Format
 ======
 

>From 21be60a590141896713536941f2d3db5f8508733 Mon Sep 17 00:00:00 2001
From: Justin Stitt <justinstitt at google.com>
Date: Wed, 4 Sep 2024 16:53:35 -0700
Subject: [PATCH 3/6] fix formatting on docs

Signed-off-by: Justin Stitt <justinstitt at google.com>
---
 clang/test/CodeGen/ubsan-type-ignorelist.cpp | 34 ++++++++++----------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/clang/test/CodeGen/ubsan-type-ignorelist.cpp b/clang/test/CodeGen/ubsan-type-ignorelist.cpp
index 2364b692e53160..e8b14d5c415222 100644
--- a/clang/test/CodeGen/ubsan-type-ignorelist.cpp
+++ b/clang/test/CodeGen/ubsan-type-ignorelist.cpp
@@ -25,8 +25,8 @@
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=vptr -fsanitize-recover=vptr -fsanitize-ignorelist=%t-type.ignorelist -emit-llvm %s -o - | FileCheck %s --check-prefix=VPTR-TYPE
 
 class Bar {
-  public:
-    virtual ~Bar() {}
+public:
+  virtual ~Bar() {}
 };
 class Foo : public Bar {};
 
@@ -35,21 +35,21 @@ Bar bar;
 // VPTR: @_Z7checkmev
 // VPTR-TYPE: @_Z7checkmev
 void checkme() {
-  // VPTR: call void @__ubsan_handle_dynamic_type_cache_miss({{.*}} (ptr @bar to
-  // VPTR-TYPE-NOT: @__ubsan_handle_dynamic_type_cache_miss
+// VPTR: call void @__ubsan_handle_dynamic_type_cache_miss({{.*}} (ptr @bar to
+// VPTR-TYPE-NOT: @__ubsan_handle_dynamic_type_cache_miss
   Foo* foo = static_cast<Foo*>(&bar); // down-casting
-                                      // VPTR: ret void
-                                      // VPTR-TYPE: ret void
+// VPTR: ret void
+// VPTR-TYPE: ret void
   return;
 }
 
 // INT-LABEL: ignore_int
 void ignore_int(int A, int B, unsigned C, unsigned D, long E) {
-  // INT: llvm.uadd.with.overflow.i32
+// INT: llvm.uadd.with.overflow.i32
   (void)(C+D);
-  // INT-NOT: llvm.sadd.with.overflow.i32
+// INT-NOT: llvm.sadd.with.overflow.i32
   (void)(A+B);
-  // INT: llvm.sadd.with.overflow.i64
+// INT: llvm.sadd.with.overflow.i64
   (void)(++E);
 }
 
@@ -59,16 +59,16 @@ typedef myty derivative;
 // INT-LABEL: ignore_all_except_myty
 // MYTY-LABEL: ignore_all_except_myty
 void ignore_all_except_myty(myty A, myty B, int C, unsigned D, derivative E) {
-  // MYTY-NOT: llvm.sadd.with.overflow.i32
+// MYTY-NOT: llvm.sadd.with.overflow.i32
   (void)(++C);
 
-  // MYTY-NOT: llvm.uadd.with.overflow.i32
+// MYTY-NOT: llvm.uadd.with.overflow.i32
   (void)(D+D);
 
-  // MYTY-NOT: llvm.umul.with.overflow.i64
+// MYTY-NOT: llvm.umul.with.overflow.i64
   (void)(E*2);
 
-  // MYTY: llvm.uadd.with.overflow.i64
+// MYTY: llvm.uadd.with.overflow.i64
   (void)(A+B);
 }
 
@@ -76,14 +76,14 @@ void ignore_all_except_myty(myty A, myty B, int C, unsigned D, derivative E) {
 // MYTY-LABEL: truncation
 // TRUNC-LABEL: truncation
 void truncation(char A, int B, unsigned char C, short D) {
-  // TRUNC-NOT: %handler.implicit_conversion
+// TRUNC-NOT: %handler.implicit_conversion
   A = B;
-  // TRUNC-NOT: %handler.implicit_conversion
+// TRUNC-NOT: %handler.implicit_conversion
   A = C;
-  // TRUNC-NOT: %handler.implicit_conversion
+// TRUNC-NOT: %handler.implicit_conversion
   C = B;
 
-  // TRUNC: %handler.implicit_conversion
+// TRUNC: %handler.implicit_conversion
   D = B;
 
   (void)A;

>From ce2a8086ad113cec0d6d6bd5c7077fe120f6db03 Mon Sep 17 00:00:00 2001
From: Justin Stitt <justinstitt at google.com>
Date: Wed, 25 Sep 2024 12:25:36 -0700
Subject: [PATCH 4/6] use split-file for tests

Signed-off-by: Justin Stitt <justinstitt at google.com>
---
 ...orelist.cpp => ubsan-type-ignorelist.test} | 52 ++++++++++++-------
 1 file changed, 33 insertions(+), 19 deletions(-)
 rename clang/test/CodeGen/{ubsan-type-ignorelist.cpp => ubsan-type-ignorelist.test} (64%)

diff --git a/clang/test/CodeGen/ubsan-type-ignorelist.cpp b/clang/test/CodeGen/ubsan-type-ignorelist.test
similarity index 64%
rename from clang/test/CodeGen/ubsan-type-ignorelist.cpp
rename to clang/test/CodeGen/ubsan-type-ignorelist.test
index e8b14d5c415222..14f297fcec2065 100644
--- a/clang/test/CodeGen/ubsan-type-ignorelist.cpp
+++ b/clang/test/CodeGen/ubsan-type-ignorelist.test
@@ -1,29 +1,43 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+
 // Verify ubsan doesn't emit checks for ignorelisted types
-// RUN: echo "[{unsigned-integer-overflow,signed-integer-overflow}]" > %t-int.ignorelist
-// RUN: echo "type:int" >> %t-int.ignorelist
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t-int.ignorelist -emit-llvm %s -o - | FileCheck %s --check-prefix=INT
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/int.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=INT
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/nosection.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=INT
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/allow-same-as-no-category.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=INT
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/myty.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=MYTY
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=implicit-signed-integer-truncation,implicit-unsigned-integer-truncation -fsanitize-ignorelist=%t/trunc.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=TRUNC
+
+// Verify ubsan vptr does not check down-casts on ignorelisted types.
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=vptr -fsanitize-recover=vptr -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=VPTR
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=vptr -fsanitize-recover=vptr -fsanitize-ignorelist=%t/vptr.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=VPTR-TYPE
 
-// RUN: echo "type:int" > %t-nosection.ignorelist
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t-nosection.ignorelist -emit-llvm %s -o - | FileCheck %s --check-prefix=INT
 
-// RUN: echo "type:int=allow" > %t-allow-same-as-no-category.ignorelist
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t-allow-same-as-no-category.ignorelist -emit-llvm %s -o - | FileCheck %s --check-prefix=INT
+//--- int.ignorelist
+[{unsigned-integer-overflow,signed-integer-overflow}]
+type:int
 
-// RUN: echo "[{unsigned-integer-overflow,signed-integer-overflow}]" > %t-myty.ignorelist
-// RUN: echo "type:*" >> %t-myty.ignorelist
-// RUN: echo "type:myty=skip" >> %t-myty.ignorelist
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t-myty.ignorelist -emit-llvm %s -o - | FileCheck %s --check-prefix=MYTY
+//--- nosection.ignorelist
+type:int
 
-// RUN: echo "[{implicit-signed-integer-truncation,implicit-unsigned-integer-truncation}]" > %t-trunc.ignorelist
-// RUN: echo "type:char" >> %t-trunc.ignorelist
-// RUN: echo "type:unsigned char" >> %t-trunc.ignorelist
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=implicit-signed-integer-truncation,implicit-unsigned-integer-truncation -fsanitize-ignorelist=%t-trunc.ignorelist -emit-llvm %s -o - | FileCheck %s --check-prefix=TRUNC
+//--- allow-same-as-no-category.ignorelist
+type:int=allow
 
-// Verify ubsan vptr does not check down-casts on ignorelisted types.
-// RUN: echo "type:_ZTI3Foo" > %t-type.ignorelist
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=vptr -fsanitize-recover=vptr -emit-llvm %s -o - | FileCheck %s --check-prefix=VPTR
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=vptr -fsanitize-recover=vptr -fsanitize-ignorelist=%t-type.ignorelist -emit-llvm %s -o - | FileCheck %s --check-prefix=VPTR-TYPE
+//--- myty.ignorelist
+[{unsigned-integer-overflow,signed-integer-overflow}]
+type:*
+type:myty=skip
+
+//--- trunc.ignorelist
+[{implicit-signed-integer-truncation,implicit-unsigned-integer-truncation}]
+type:char
+type:unsigned char
+
+
+//--- vptr.ignorelist
+type:_ZTI3Foo
 
+//--- test.cpp
 class Bar {
 public:
   virtual ~Bar() {}

>From 7f92e75930d5c69249c636c1e454519211b9a5f2 Mon Sep 17 00:00:00 2001
From: Justin Stitt <justinstitt at google.com>
Date: Wed, 25 Sep 2024 16:17:51 -0700
Subject: [PATCH 5/6] use no_sanitize and sanitize over allow and skip/forbid

Signed-off-by: Justin Stitt <justinstitt at google.com>
---
 clang/docs/SanitizerSpecialCaseList.rst       | 23 +++++++----------
 clang/lib/AST/ASTContext.cpp                  | 25 ++++++-------------
 clang/test/CodeGen/ubsan-type-ignorelist.test |  8 +++---
 3 files changed, 21 insertions(+), 35 deletions(-)

diff --git a/clang/docs/SanitizerSpecialCaseList.rst b/clang/docs/SanitizerSpecialCaseList.rst
index 13f71b878d4cc8..6ca8bb632082e1 100644
--- a/clang/docs/SanitizerSpecialCaseList.rst
+++ b/clang/docs/SanitizerSpecialCaseList.rst
@@ -75,12 +75,13 @@ Supplying ``ignorelist.txt`` with ``-fsanitize-ignorelist=ignorelist.txt``
 disables overflow sanitizer instrumentation for arithmetic operations
 containing values of type ``int``, for example. Custom types may be used.
 
-The following SCL categories are supported: ``=allow``, ``=skip`` and
-``=forbid``. The ``allow`` category is the default for any entry and specifies
-that the query, if matched, will have its sanitizer instrumentation ignored.
-Conversely, both ``skip`` and ``forbid`` cause their queries, if matched, to be
-left out of the ignorelist -- essentially ensuring sanitizer instrumentation
-remains for those types. This is useful for whitelisting specific types.
+The following SCL categories are supported: ``=no_sanitize`` and ``=sanitize``.
+The ``no_sanitize`` category is the default for any entry within an ignorelist
+and specifies that the query, if matched, will have its sanitizer
+instrumentation ignored. Conversely, ``sanitize`` causes its queries, if
+matched, to be left out of the ignorelist -- essentially ensuring sanitizer
+instrumentation remains for those types. This is useful for whitelisting
+specific types.
 
 With this, one may disable instrumentation for all types and specifically allow
 instrumentation for one or many types.
@@ -89,8 +90,8 @@ instrumentation for one or many types.
 
   $ cat ignorelist.txt
   [implicit-signed-integer-truncation]
-  type:*=allow
-  type:T=skip
+  type:*=no_sanitize
+  type:T=sanitize
   $ cat foo.c
   typedef char T;
   typedef char U;
@@ -100,12 +101,6 @@ instrumentation for one or many types.
     char c = toobig; // also not instrumented
   }
 
-Note that ``skip`` and ``forbid`` operate exactly the same in this context and
-both options exist simply for conformity with the `-fprofile-list
-<https://clang.llvm.org/docs/UsersManual.html#instrumenting-only-selected-files-or-functions>`_
-syntax for adjusting profile instrumentation. You do not need to specify any
-`default:<type>` for ``-fsanitize-ignorelist`` SSCLs, though.
-
 Format
 ======
 
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 4270ddc90b7b24..f03bacec83ca7c 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -836,30 +836,21 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
 /// For example:
 /// ignorelist.txt>
 /// [{unsigned-integer-overflow,signed-integer-overflow}]
-/// type:*
-/// type:size_t=skip
+/// type:*=no_sanitize
+/// type:size_t=sanitize
 /// <ignorelist.txt
 /// Supplying the above ignorelist.txt will disable overflow sanitizer
 /// instrumentation for all types except "size_t".
 bool ASTContext::isTypeIgnoredBySanitizer(const SanitizerMask &Mask,
                                           const QualType &Ty) const {
-  // One may specifically allow a type "type:foo=allow"
-  bool isAllowedBySCL =
-      NoSanitizeL->containsType(Mask, Ty.getAsString(), "allow");
+  bool sanitizeType =
+      NoSanitizeL->containsType(Mask, Ty.getAsString(), "sanitize");
 
-  // There could also be no category present "type:foo", which is the same as
-  // "allow"
-  isAllowedBySCL |= NoSanitizeL->containsType(Mask, Ty.getAsString());
+  bool noSanitizeType =
+      NoSanitizeL->containsType(Mask, Ty.getAsString(), "no_sanitize") ||
+      NoSanitizeL->containsType(Mask, Ty.getAsString());
 
-  // Explicitly specifying "skip" is also possible "type:foo=skip"
-  bool isSkippedBySCL =
-      NoSanitizeL->containsType(Mask, Ty.getAsString(), "skip");
-
-  // Or "forbid", as there is currently no distinction between "skip" and
-  // "forbid" for the purposes of the overflow/truncation sanitizer ignorelist.
-  isSkippedBySCL |= NoSanitizeL->containsType(Mask, Ty.getAsString(), "forbid");
-
-  return isAllowedBySCL && !isSkippedBySCL;
+  return noSanitizeType && !sanitizeType;
 }
 
 TargetCXXABI::Kind ASTContext::getCXXABIKind() const {
diff --git a/clang/test/CodeGen/ubsan-type-ignorelist.test b/clang/test/CodeGen/ubsan-type-ignorelist.test
index 14f297fcec2065..f5762d21548532 100644
--- a/clang/test/CodeGen/ubsan-type-ignorelist.test
+++ b/clang/test/CodeGen/ubsan-type-ignorelist.test
@@ -4,7 +4,7 @@
 // Verify ubsan doesn't emit checks for ignorelisted types
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/int.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=INT
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/nosection.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=INT
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/allow-same-as-no-category.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=INT
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/nosan-same-as-no-category.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=INT
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/myty.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=MYTY
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=implicit-signed-integer-truncation,implicit-unsigned-integer-truncation -fsanitize-ignorelist=%t/trunc.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=TRUNC
 
@@ -20,13 +20,13 @@ type:int
 //--- nosection.ignorelist
 type:int
 
-//--- allow-same-as-no-category.ignorelist
-type:int=allow
+//--- nosan-same-as-no-category.ignorelist
+type:int=no_sanitize
 
 //--- myty.ignorelist
 [{unsigned-integer-overflow,signed-integer-overflow}]
 type:*
-type:myty=skip
+type:myty=sanitize
 
 //--- trunc.ignorelist
 [{implicit-signed-integer-truncation,implicit-unsigned-integer-truncation}]

>From f119326d87b2646d65636b8101a17a262f7461d7 Mon Sep 17 00:00:00 2001
From: Justin Stitt <justinstitt at google.com>
Date: Wed, 30 Oct 2024 11:00:04 -0700
Subject: [PATCH 6/6] rephrase some documentation for readability's sake

Signed-off-by: Justin Stitt <justinstitt at google.com>
---
 clang/docs/SanitizerSpecialCaseList.rst | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/clang/docs/SanitizerSpecialCaseList.rst b/clang/docs/SanitizerSpecialCaseList.rst
index 6ca8bb632082e1..3c3659dd149af0 100644
--- a/clang/docs/SanitizerSpecialCaseList.rst
+++ b/clang/docs/SanitizerSpecialCaseList.rst
@@ -71,9 +71,9 @@ instrumentation based on type.
   $ clang -fsanitize=signed-integer-overflow -fsanitize-ignorelist=ignorelist.txt foo.c ; ./a.out
   # no signed-integer-overflow error
 
-Supplying ``ignorelist.txt`` with ``-fsanitize-ignorelist=ignorelist.txt``
-disables overflow sanitizer instrumentation for arithmetic operations
-containing values of type ``int``, for example. Custom types may be used.
+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 following SCL categories are supported: ``=no_sanitize`` and ``=sanitize``.
 The ``no_sanitize`` category is the default for any entry within an ignorelist
@@ -84,7 +84,8 @@ instrumentation remains for those types. This is useful for whitelisting
 specific types.
 
 With this, one may disable instrumentation for all types and specifically allow
-instrumentation for one or many types.
+instrumentation for one or many types -- including types created via
+``typedef``.
 
 .. code-block:: bash
 



More information about the cfe-commits mailing list