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 <justinst...@google.com> Date: Tue, 3 Sep 2024 18:28:53 -0700 Subject: [PATCH 01/13] hook up sscl categories with overflow/truncation sanitizers Signed-off-by: Justin Stitt <justinst...@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 <justinst...@google.com> Date: Wed, 4 Sep 2024 15:43:21 -0700 Subject: [PATCH 02/13] add docs Signed-off-by: Justin Stitt <justinst...@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 <justinst...@google.com> Date: Wed, 4 Sep 2024 16:53:35 -0700 Subject: [PATCH 03/13] fix formatting on docs Signed-off-by: Justin Stitt <justinst...@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 <justinst...@google.com> Date: Wed, 25 Sep 2024 12:25:36 -0700 Subject: [PATCH 04/13] use split-file for tests Signed-off-by: Justin Stitt <justinst...@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 <justinst...@google.com> Date: Wed, 25 Sep 2024 16:17:51 -0700 Subject: [PATCH 05/13] use no_sanitize and sanitize over allow and skip/forbid Signed-off-by: Justin Stitt <justinst...@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 <justinst...@google.com> Date: Wed, 30 Oct 2024 11:00:04 -0700 Subject: [PATCH 06/13] rephrase some documentation for readability's sake Signed-off-by: Justin Stitt <justinst...@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 >From d670482ca0dec24f49e2568351fdd5f42badfb17 Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Wed, 30 Oct 2024 18:44:55 -0700 Subject: [PATCH 07/13] fix improper link formatting Signed-off-by: Justin Stitt <justinst...@google.com> --- clang/docs/SanitizerSpecialCaseList.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/docs/SanitizerSpecialCaseList.rst b/clang/docs/SanitizerSpecialCaseList.rst index 3c3659dd149af0..ab1f1954d9bfbe 100644 --- a/clang/docs/SanitizerSpecialCaseList.rst +++ b/clang/docs/SanitizerSpecialCaseList.rst @@ -16,9 +16,8 @@ Goal and usage ============== 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: +: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; * ignore a function that does some low-level magic (e.g. walks through the >From 8e473070c9045395d627bfece040e7d7985c0943 Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Wed, 30 Oct 2024 19:59:26 -0700 Subject: [PATCH 08/13] readd removed test Signed-off-by: Justin Stitt <justinst...@google.com> --- clang/test/CodeGen/ubsan-type-ignorelist.cpp | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 clang/test/CodeGen/ubsan-type-ignorelist.cpp diff --git a/clang/test/CodeGen/ubsan-type-ignorelist.cpp b/clang/test/CodeGen/ubsan-type-ignorelist.cpp new file mode 100644 index 00000000000000..7bea84f5fabb93 --- /dev/null +++ b/clang/test/CodeGen/ubsan-type-ignorelist.cpp @@ -0,0 +1,23 @@ +// 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 + +class Bar { +public: + virtual ~Bar() {} +}; +class Foo : public Bar {}; + +Bar bar; + +// DEFAULT: @_Z7checkmev +// TYPE: @_Z7checkmev +void checkme() { +// DEFAULT: call void @__ubsan_handle_dynamic_type_cache_miss({{.*}} (ptr @bar to +// TYPE-NOT: @__ubsan_handle_dynamic_type_cache_miss + Foo* foo = static_cast<Foo*>(&bar); // down-casting +// DEFAULT: ret void +// TYPE: ret void + return; +} >From 33aa461aeaea6e42aea80745b5bf3fbeab6c5499 Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Wed, 30 Oct 2024 20:00:18 -0700 Subject: [PATCH 09/13] add new test for category precedence, rename pre-existing test Signed-off-by: Justin Stitt <justinst...@google.com> --- .../ubsan-type-ignorelist-category-2.test | 58 +++++++++++++++++++ ...st => ubsan-type-ignorelist-category.test} | 28 --------- 2 files changed, 58 insertions(+), 28 deletions(-) create mode 100644 clang/test/CodeGen/ubsan-type-ignorelist-category-2.test rename clang/test/CodeGen/{ubsan-type-ignorelist.test => ubsan-type-ignorelist-category.test} (76%) diff --git a/clang/test/CodeGen/ubsan-type-ignorelist-category-2.test b/clang/test/CodeGen/ubsan-type-ignorelist-category-2.test new file mode 100644 index 00000000000000..79b506ebdb97ea --- /dev/null +++ b/clang/test/CodeGen/ubsan-type-ignorelist-category-2.test @@ -0,0 +1,58 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t + +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-0.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-1.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-2.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-3.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-4.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-5.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-6.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-ignorelist=%t/order-7.ignorelist -emit-llvm %t/test.c -o - | FileCheck %s + +// The same type can appear multiple times within an ignorelist. This is a test +// to make sure "=sanitize" has priority regardless of the order in which +// duplicate type entries appear. This is a precautionary measure; we would +// much rather eagerly sanitize than silently forgo sanitization. + +//--- order-0.ignorelist +type:int=no_sanitize +type:int=sanitize + +//--- order-1.ignorelist +type:int=sanitize +type:int=no_sanitize + +//--- order-2.ignorelist +type:in*=no_sanitize +type:int=sanitize + +//--- order-3.ignorelist +type:in*=sanitize +type:int=no_sanitize + +//--- order-4.ignorelist +type:int=no_sanitize +type:in*=sanitize + +//--- order-5.ignorelist +type:int=sanitize +type:in*=no_sanitize + +//--- order-6.ignorelist +type:int=sanitize +type:in* + +//--- order-7.ignorelist +type:int +type:int=sanitize + + + + +//--- test.c +// CHECK-LABEL: @test +void test(int A) { +// CHECK: @llvm.sadd.with.overflow.i32 + ++A; +} diff --git a/clang/test/CodeGen/ubsan-type-ignorelist.test b/clang/test/CodeGen/ubsan-type-ignorelist-category.test similarity index 76% rename from clang/test/CodeGen/ubsan-type-ignorelist.test rename to clang/test/CodeGen/ubsan-type-ignorelist-category.test index f5762d21548532..795272971de0b5 100644 --- a/clang/test/CodeGen/ubsan-type-ignorelist.test +++ b/clang/test/CodeGen/ubsan-type-ignorelist-category.test @@ -8,11 +8,6 @@ // 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 - - //--- int.ignorelist [{unsigned-integer-overflow,signed-integer-overflow}] type:int @@ -33,30 +28,7 @@ type:myty=sanitize type:char type:unsigned char - -//--- vptr.ignorelist -type:_ZTI3Foo - //--- test.cpp -class Bar { -public: - virtual ~Bar() {} -}; -class Foo : public Bar {}; - -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 - Foo* foo = static_cast<Foo*>(&bar); // down-casting -// 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 >From 4eba983ebfafab7b5ffff00047b5d09bb1fa72c7 Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Wed, 30 Oct 2024 20:04:41 -0700 Subject: [PATCH 10/13] add clarification about category reordering to docs Signed-off-by: Justin Stitt <justinst...@google.com> --- clang/docs/SanitizerSpecialCaseList.rst | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/clang/docs/SanitizerSpecialCaseList.rst b/clang/docs/SanitizerSpecialCaseList.rst index ab1f1954d9bfbe..0edd4566190ac9 100644 --- a/clang/docs/SanitizerSpecialCaseList.rst +++ b/clang/docs/SanitizerSpecialCaseList.rst @@ -80,11 +80,15 @@ 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. +specific types. If multiple entries for the same type exist, those with the +``sanitize`` category take precedence. -With this, one may disable instrumentation for all types and specifically allow -instrumentation for one or many types -- including types created via -``typedef``. +With this, one may disable instrumentation for some or all types and +specifically allow instrumentation for one or many types -- including types +created via ``typedef``. + +The example below shows how one may control the signed truncation sanitizer for +various types. .. code-block:: bash @@ -92,6 +96,7 @@ instrumentation for one or many types -- including types created via [implicit-signed-integer-truncation] type:*=no_sanitize type:T=sanitize + $ cat foo.c typedef char T; typedef char U; >From 651bc7d2872a8f2b74a7c940f0ebe262e31dfc90 Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Wed, 30 Oct 2024 21:20:06 -0700 Subject: [PATCH 11/13] use better comparison logic Signed-off-by: Justin Stitt <justinst...@google.com> --- clang/lib/AST/ASTContext.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index f03bacec83ca7c..a0aeb762557ae8 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -843,14 +843,9 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( /// instrumentation for all types except "size_t". bool ASTContext::isTypeIgnoredBySanitizer(const SanitizerMask &Mask, const QualType &Ty) const { - bool sanitizeType = - NoSanitizeL->containsType(Mask, Ty.getAsString(), "sanitize"); - - bool noSanitizeType = - NoSanitizeL->containsType(Mask, Ty.getAsString(), "no_sanitize") || - NoSanitizeL->containsType(Mask, Ty.getAsString()); - - return noSanitizeType && !sanitizeType; + return (NoSanitizeL->containsType(Mask, Ty.getAsString()) || + NoSanitizeL->containsType(Mask, Ty.getAsString(), "no_sanitize")) && + !NoSanitizeL->containsType(Mask, Ty.getAsString(), "sanitize"); } TargetCXXABI::Kind ASTContext::getCXXABIKind() const { >From 7156afbb011b8c6e22a0585991ae4d3f6e9ccdc4 Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Wed, 30 Oct 2024 22:05:35 -0700 Subject: [PATCH 12/13] use printing policy for type name Signed-off-by: Justin Stitt <justinst...@google.com> --- clang/lib/AST/ASTContext.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a0aeb762557ae8..48023389499517 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -843,9 +843,11 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( /// instrumentation for all types except "size_t". bool ASTContext::isTypeIgnoredBySanitizer(const SanitizerMask &Mask, const QualType &Ty) const { - return (NoSanitizeL->containsType(Mask, Ty.getAsString()) || - NoSanitizeL->containsType(Mask, Ty.getAsString(), "no_sanitize")) && - !NoSanitizeL->containsType(Mask, Ty.getAsString(), "sanitize"); + std::string TyName = Ty.getUnqualifiedType().getAsString(getPrintingPolicy()); + + return (NoSanitizeL->containsType(Mask, TyName) || + NoSanitizeL->containsType(Mask, TyName, "no_sanitize")) && + !NoSanitizeL->containsType(Mask, TyName, "sanitize"); } TargetCXXABI::Kind ASTContext::getCXXABIKind() const { >From b4a9448d2c8478849fb38d7066f33a609b76fe7b Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Fri, 1 Nov 2024 16:11:07 -0700 Subject: [PATCH 13/13] remove no_sanitize category Signed-off-by: Justin Stitt <justinst...@google.com> --- clang/docs/SanitizerSpecialCaseList.rst | 23 ++++++++----------- clang/lib/AST/ASTContext.cpp | 16 +++---------- .../ubsan-type-ignorelist-category-2.test | 12 +++++----- .../ubsan-type-ignorelist-category.test | 23 ++++++++++++++++++- 4 files changed, 41 insertions(+), 33 deletions(-) diff --git a/clang/docs/SanitizerSpecialCaseList.rst b/clang/docs/SanitizerSpecialCaseList.rst index 0edd4566190ac9..96a7b2fba4ae43 100644 --- a/clang/docs/SanitizerSpecialCaseList.rst +++ b/clang/docs/SanitizerSpecialCaseList.rst @@ -57,6 +57,9 @@ sanitizers ``implicit-signed-integer-truncation`` and ``implicit-unsigned-integer-truncation`` support the ability to adjust instrumentation based on type. +By default, supported sanitizers will have their instrumentation disabled for +types specified within an ignorelist. + .. code-block:: bash $ cat foo.c @@ -74,27 +77,21 @@ 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 -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. If multiple entries for the same type exist, those with the -``sanitize`` category take precedence. +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. With this, one may disable instrumentation for some or all types and specifically allow instrumentation for one or many types -- including types -created via ``typedef``. - -The example below shows how one may control the signed truncation sanitizer for -various types. +created via ``typedef``. This is a way to achieve a sort of "allowlist" for +supported sanitizers. .. code-block:: bash $ cat ignorelist.txt [implicit-signed-integer-truncation] - type:*=no_sanitize + type:* type:T=sanitize $ cat foo.c diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 48023389499517..a1227448be16f1 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -831,22 +831,12 @@ 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:*=no_sanitize -/// type:size_t=sanitize -/// <ignorelist.txt -/// Supplying the above ignorelist.txt will disable overflow sanitizer -/// instrumentation for all types except "size_t". +/// Check if a type can have its sanitizer instrumentation elided based on its +/// presence within an ignorelist. bool ASTContext::isTypeIgnoredBySanitizer(const SanitizerMask &Mask, const QualType &Ty) const { std::string TyName = Ty.getUnqualifiedType().getAsString(getPrintingPolicy()); - - return (NoSanitizeL->containsType(Mask, TyName) || - NoSanitizeL->containsType(Mask, TyName, "no_sanitize")) && + return NoSanitizeL->containsType(Mask, TyName) && !NoSanitizeL->containsType(Mask, TyName, "sanitize"); } diff --git a/clang/test/CodeGen/ubsan-type-ignorelist-category-2.test b/clang/test/CodeGen/ubsan-type-ignorelist-category-2.test index 79b506ebdb97ea..4b4f87326dbe59 100644 --- a/clang/test/CodeGen/ubsan-type-ignorelist-category-2.test +++ b/clang/test/CodeGen/ubsan-type-ignorelist-category-2.test @@ -16,28 +16,28 @@ // much rather eagerly sanitize than silently forgo sanitization. //--- order-0.ignorelist -type:int=no_sanitize +type:int type:int=sanitize //--- order-1.ignorelist type:int=sanitize -type:int=no_sanitize +type:int //--- order-2.ignorelist -type:in*=no_sanitize +type:in* type:int=sanitize //--- order-3.ignorelist type:in*=sanitize -type:int=no_sanitize +type:int //--- order-4.ignorelist -type:int=no_sanitize +type:int type:in*=sanitize //--- order-5.ignorelist type:int=sanitize -type:in*=no_sanitize +type:in* //--- order-6.ignorelist type:int=sanitize diff --git a/clang/test/CodeGen/ubsan-type-ignorelist-category.test b/clang/test/CodeGen/ubsan-type-ignorelist-category.test index 795272971de0b5..500c58f2165c43 100644 --- a/clang/test/CodeGen/ubsan-type-ignorelist-category.test +++ b/clang/test/CodeGen/ubsan-type-ignorelist-category.test @@ -7,6 +7,7 @@ // 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 +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=implicit-signed-integer-truncation,implicit-unsigned-integer-truncation -fsanitize-ignorelist=%t/docs.ignorelist -emit-llvm %t/test.cpp -o - | FileCheck %s --check-prefix=TRUNC2 //--- int.ignorelist [{unsigned-integer-overflow,signed-integer-overflow}] @@ -16,7 +17,7 @@ type:int type:int //--- nosan-same-as-no-category.ignorelist -type:int=no_sanitize +type:int //--- myty.ignorelist [{unsigned-integer-overflow,signed-integer-overflow}] @@ -28,6 +29,11 @@ type:myty=sanitize type:char type:unsigned char +//--- docs.ignorelist +[implicit-signed-integer-truncation] +type:* +type:T=sanitize + //--- test.cpp // INT-LABEL: ignore_int void ignore_int(int A, int B, unsigned C, unsigned D, long E) { @@ -75,3 +81,18 @@ void truncation(char A, int B, unsigned char C, short D) { (void)A; (void)D; } + + +// Matches the example from clang/docs/SanitizerSpecialCaseList.rst +typedef char T; +typedef char U; +// TRUNC2-LABEL: docs_example +void docs_example(int toobig) { +// TRUNC2: %handler.implicit_conversion + T a = toobig; +// TRUNC2-NOT: %handler.implicit_conversion + U b = toobig; +// TRUNC2-NOT: %handler.implicit_conversion + char c = toobig; +} + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits