[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