https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/80089
>From 7774e4036ac1de7fdf5fe4c6b3208b492853ffc5 Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Tue, 23 Jan 2024 23:28:42 +0000 Subject: [PATCH 1/8] add signed-integer-wrap sanitizer --- clang/include/clang/Basic/Sanitizers.def | 5 +- clang/lib/CodeGen/CGExprScalar.cpp | 62 +++++++++++++++++++----- compiler-rt/lib/ubsan/ubsan_checks.inc | 2 + 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def index c2137e3f61f645..b987b26f93c39a 100644 --- a/clang/include/clang/Basic/Sanitizers.def +++ b/clang/include/clang/Basic/Sanitizers.def @@ -104,6 +104,7 @@ SANITIZER("shift-base", ShiftBase) SANITIZER("shift-exponent", ShiftExponent) SANITIZER_GROUP("shift", Shift, ShiftBase | ShiftExponent) SANITIZER("signed-integer-overflow", SignedIntegerOverflow) +SANITIZER("signed-integer-wrap", SignedIntegerWrap) SANITIZER("unreachable", Unreachable) SANITIZER("vla-bound", VLABound) SANITIZER("vptr", Vptr) @@ -144,7 +145,7 @@ SANITIZER_GROUP("undefined", Undefined, IntegerDivideByZero | NonnullAttribute | Null | ObjectSize | PointerOverflow | Return | ReturnsNonnullAttribute | Shift | SignedIntegerOverflow | Unreachable | VLABound | Function | - Vptr) + Vptr | SignedIntegerWrap) // -fsanitize=undefined-trap is an alias for -fsanitize=undefined. SANITIZER_GROUP("undefined-trap", UndefinedTrap, Undefined) @@ -179,7 +180,7 @@ SANITIZER_GROUP("implicit-conversion", ImplicitConversion, SANITIZER_GROUP("integer", Integer, ImplicitConversion | IntegerDivideByZero | Shift | SignedIntegerOverflow | UnsignedIntegerOverflow | - UnsignedShiftBase) + UnsignedShiftBase | SignedIntegerWrap) SANITIZER("local-bounds", LocalBounds) SANITIZER_GROUP("bounds", Bounds, ArrayBounds | LocalBounds) diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index aa805f291d1757..5c05a0d7524244 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -723,6 +723,11 @@ class ScalarExprEmitter if (Ops.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: + if (CGF.SanOpts.has(SanitizerKind::SignedIntegerWrap)) { + if (CanElideOverflowCheck(CGF.getContext(), Ops)) + return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul"); + return EmitOverflowCheckedBinOp(Ops); + } return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) @@ -2516,6 +2521,12 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior( StringRef Name = IsInc ? "inc" : "dec"; switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: + if (CGF.SanOpts.has(SanitizerKind::SignedIntegerWrap)) { + if (!E->canOverflow()) + return Builder.CreateNSWAdd(InVal, Amount, Name); + return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec( + E, InVal, IsInc, E->getFPFeaturesInEffect(CGF.getLangOpts()))); + } return Builder.CreateAdd(InVal, Amount, Name); case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) @@ -3409,7 +3420,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) { - SmallVector<std::pair<llvm::Value *, SanitizerMask>, 2> Checks; + SmallVector<std::pair<llvm::Value *, SanitizerMask>, 3> Checks; if (CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero)) { Checks.push_back(std::make_pair(Builder.CreateICmpNE(Ops.RHS, Zero), @@ -3417,7 +3428,8 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( } const auto *BO = cast<BinaryOperator>(Ops.E); - if (CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow) && + if (CGF.SanOpts.hasOneOf(SanitizerKind::SignedIntegerOverflow | + SanitizerKind::SignedIntegerWrap) && Ops.Ty->hasSignedIntegerRepresentation() && !IsWidenedIntegerOp(CGF.getContext(), BO->getLHS()) && Ops.mayHaveIntegerOverflow()) { @@ -3430,8 +3442,13 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( llvm::Value *LHSCmp = Builder.CreateICmpNE(Ops.LHS, IntMin); llvm::Value *RHSCmp = Builder.CreateICmpNE(Ops.RHS, NegOne); llvm::Value *NotOverflow = Builder.CreateOr(LHSCmp, RHSCmp, "or"); - Checks.push_back( - std::make_pair(NotOverflow, SanitizerKind::SignedIntegerOverflow)); + if (CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) + Checks.push_back( + std::make_pair(NotOverflow, SanitizerKind::SignedIntegerOverflow)); + if (CGF.SanOpts.has(SanitizerKind::SignedIntegerWrap)) + Checks.push_back( + std::make_pair(NotOverflow, SanitizerKind::SignedIntegerWrap)); + } if (Checks.size() > 0) @@ -3441,8 +3458,9 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { { CodeGenFunction::SanitizerScope SanScope(&CGF); - if ((CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero) || - CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) && + if (CGF.SanOpts.hasOneOf(SanitizerKind::IntegerDivideByZero | + SanitizerKind::SignedIntegerOverflow | + SanitizerKind::SignedIntegerWrap) && Ops.Ty->isIntegerType() && (Ops.mayHaveIntegerDivisionByZero() || Ops.mayHaveIntegerOverflow())) { llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty)); @@ -3490,8 +3508,9 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { // Rem in C can't be a floating point type: C99 6.5.5p2. - if ((CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero) || - CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) && + if (CGF.SanOpts.hasOneOf(SanitizerKind::IntegerDivideByZero | + SanitizerKind::SignedIntegerOverflow | + SanitizerKind::SignedIntegerWrap) && Ops.Ty->isIntegerType() && (Ops.mayHaveIntegerDivisionByZero() || Ops.mayHaveIntegerOverflow())) { CodeGenFunction::SanitizerScope SanScope(&CGF); @@ -3553,12 +3572,19 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { const std::string *handlerName = &CGF.getLangOpts().OverflowHandler; if (handlerName->empty()) { - // If the signed-integer-overflow sanitizer is enabled, emit a call to its - // runtime. Otherwise, this is a -ftrapv check, so just emit a trap. - if (!isSigned || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) { + // If the signed-integer-overflow or signed-integer-wrap sanitizer is + // enabled, emit a call to its runtime. Otherwise, this is a -ftrapv check, + // so just emit a trap. + if (!isSigned || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow) + || CGF.SanOpts.has(SanitizerKind::SignedIntegerWrap)) { llvm::Value *NotOverflow = Builder.CreateNot(overflow); - SanitizerMask Kind = isSigned ? SanitizerKind::SignedIntegerOverflow - : SanitizerKind::UnsignedIntegerOverflow; + + SanitizerMask Kind = SanitizerKind::UnsignedIntegerOverflow; + if (isSigned) + Kind = CGF.getLangOpts().getSignedOverflowBehavior() == + LangOptions::SOB_Defined ? SanitizerKind::SignedIntegerWrap : + SanitizerKind::SignedIntegerOverflow; + EmitBinOpCheck(std::make_pair(NotOverflow, Kind), Ops); } else CGF.EmitTrapCheck(Builder.CreateNot(overflow), OverflowKind); @@ -3861,6 +3887,11 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) { if (op.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: + if (CGF.SanOpts.has(SanitizerKind::SignedIntegerWrap)) { + if (CanElideOverflowCheck(CGF.getContext(), op)) + return Builder.CreateNSWAdd(op.LHS, op.RHS, "add"); + return EmitOverflowCheckedBinOp(op); + } return Builder.CreateAdd(op.LHS, op.RHS, "add"); case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) @@ -4015,6 +4046,11 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) { if (op.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: + if (CGF.SanOpts.has(SanitizerKind::SignedIntegerWrap)) { + if (CanElideOverflowCheck(CGF.getContext(), op)) + return Builder.CreateNSWSub(op.LHS, op.RHS, "sub"); + return EmitOverflowCheckedBinOp(op); + } return Builder.CreateSub(op.LHS, op.RHS, "sub"); case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) diff --git a/compiler-rt/lib/ubsan/ubsan_checks.inc b/compiler-rt/lib/ubsan/ubsan_checks.inc index 846cd89ee19f8b..b50ba91a158284 100644 --- a/compiler-rt/lib/ubsan/ubsan_checks.inc +++ b/compiler-rt/lib/ubsan/ubsan_checks.inc @@ -31,6 +31,8 @@ UBSAN_CHECK(AlignmentAssumption, "alignment-assumption", "alignment") UBSAN_CHECK(InsufficientObjectSize, "insufficient-object-size", "object-size") UBSAN_CHECK(SignedIntegerOverflow, "signed-integer-overflow", "signed-integer-overflow") +UBSAN_CHECK(SignedIntegerWrap, "signed-integer-wrap", + "signed-integer-wrap") UBSAN_CHECK(UnsignedIntegerOverflow, "unsigned-integer-overflow", "unsigned-integer-overflow") UBSAN_CHECK(IntegerDivideByZero, "integer-divide-by-zero", >From 7c959a1b3d04b13619132cdd4063337d3854f5d4 Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Tue, 30 Jan 2024 22:21:10 +0000 Subject: [PATCH 2/8] add frontend tests --- clang/test/Driver/fsanitize.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c index 1671825042c323..86172febf4723b 100644 --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -1,19 +1,21 @@ // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-trap=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP2 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-trap=signed-integer-wrap %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP3 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP // RUN: %clang --target=x86_64-linux-gnu -fsanitize-undefined-trap-on-error -fsanitize=undefined-trap %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP // RUN: %clang --target=x86_64-linux-gnu -fsanitize-trap -fsanitize=undefined-trap %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP // CHECK-UNDEFINED-TRAP-NOT: -fsanitize-recover -// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}} -// CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound" -// CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound" +// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|signed-integer-wrap|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){19}"}} +// CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,signed-integer-wrap,unreachable,vla-bound" +// CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-wrap,unreachable,vla-bound" +// CHECK-UNDEFINED-TRAP3: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound" // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED -// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){19}"}} +// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|signed-integer-wrap|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){20}"}} // RUN: %clang --target=x86_64-apple-darwin10 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-DARWIN -// CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){18}"}} +// CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-integer-overflow|signed-integer-wrap|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){19}"}} // RUN: %clang --target=i386-pc-win32 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-UNDEFINED-WIN32,CHECK-UNDEFINED-MSVC // RUN: %clang --target=i386-pc-win32 -fsanitize=undefined -x c++ %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-UNDEFINED-WIN32,CHECK-UNDEFINED-WIN-CXX,CHECK-UNDEFINED-MSVC @@ -24,8 +26,8 @@ // CHECK-UNDEFINED-WIN64: "--dependent-lib={{[^"]*}}ubsan_standalone{{(-x86_64)?}}.lib" // CHECK-UNDEFINED-WIN64-MINGW: "--dependent-lib={{[^"]*}}libclang_rt.ubsan_standalone{{(-x86_64)?}}.a" // CHECK-UNDEFINED-WIN-CXX: "--dependent-lib={{[^"]*}}ubsan_standalone_cxx{{[^"]*}}.lib" -// CHECK-UNDEFINED-MSVC-SAME: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}} -// CHECK-UNDEFINED-WIN64-MINGW-SAME: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|vptr),?){19}"}} +// CHECK-UNDEFINED-MSVC-SAME: "-fsanitize={{((signed-integer-overflow|signed-integer-wrap|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){19}"}} +// CHECK-UNDEFINED-WIN64-MINGW-SAME: "-fsanitize={{((signed-integer-overflow|signed-integer-wrap|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|vptr),?){20}"}} // RUN: %clang --target=i386-pc-win32 -fsanitize-coverage=bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-COVERAGE-WIN32 // CHECK-COVERAGE-WIN32: "--dependent-lib={{[^"]*}}ubsan_standalone{{(-i386)?}}.lib" @@ -33,7 +35,7 @@ // CHECK-COVERAGE-WIN64: "--dependent-lib={{[^"]*}}ubsan_standalone{{(-x86_64)?}}.lib" // RUN: %clang --target=%itanium_abi_triple -fsanitize=integer %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INTEGER -implicit-check-not="-fsanitize-address-use-after-scope" -// CHECK-INTEGER: "-fsanitize={{((signed-integer-overflow|unsigned-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|implicit-unsigned-integer-truncation|implicit-signed-integer-truncation|implicit-integer-sign-change|unsigned-shift-base),?){9}"}} +// CHECK-INTEGER: "-fsanitize={{((signed-integer-overflow|signed-integer-wrap|unsigned-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|implicit-unsigned-integer-truncation|implicit-signed-integer-truncation|implicit-integer-sign-change|unsigned-shift-base),?){10}"}} // RUN: %clang -fsanitize=implicit-conversion %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-implicit-conversion,CHECK-implicit-conversion-RECOVER // RUN: %clang -fsanitize=implicit-conversion -fsanitize-recover=implicit-conversion %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-implicit-conversion,CHECK-implicit-conversion-RECOVER @@ -90,7 +92,7 @@ // CHECK-FNO-SANITIZE-ALL: "-fsanitize=thread" // RUN: %clang --target=x86_64-linux-gnu -fsanitize=thread,undefined -fno-sanitize=thread -fno-sanitize=float-cast-overflow,vptr,bool,builtin,enum %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-UNDEFINED -// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|array-bounds|returns-nonnull-attribute|nonnull-attribute),?){14}"}} +// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|signed-integer-wrap|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|array-bounds|returns-nonnull-attribute|nonnull-attribute),?){15}"}} // RUN: %clang -fsanitize=shift -fno-sanitize=shift-base %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSANITIZE-SHIFT-PARTIAL // CHECK-FSANITIZE-SHIFT-PARTIAL: "-fsanitize=shift-exponent" @@ -351,7 +353,7 @@ // RUN: %clang --target=x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER-UBSAN // RUN: %clang --target=x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=all -fsanitize-recover=thread -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER-UBSAN // RUN: %clang --target=x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover=all -fno-sanitize-recover=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER-UBSAN -// CHECK-RECOVER-UBSAN: "-fsanitize-recover={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){17}"}} +// CHECK-RECOVER-UBSAN: "-fsanitize-recover={{((signed-integer-overflow|signed-integer-wrap|integer-divide-by-zero|function|shift-base|shift-exponent|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){18}"}} // CHECK-NO-RECOVER-UBSAN-NOT: sanitize-recover // RUN: %clang --target=x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=all -fsanitize-recover=object-size,shift-base -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-RECOVER @@ -549,7 +551,7 @@ // CHECK-ASAN-IOS: -fsanitize=address // RUN: %clang --target=i386-pc-openbsd -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-OPENBSD -// CHECK-UBSAN-OPENBSD: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){19}"}} +// CHECK-UBSAN-OPENBSD: "-fsanitize={{((signed-integer-overflow|signed-integer-wrap|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){20}"}} // RUN: not %clang --target=i386-pc-openbsd -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-OPENBSD // CHECK-ASAN-OPENBSD: unsupported option '-fsanitize=address' for target 'i386-pc-openbsd' @@ -837,14 +839,14 @@ // CHECK-TSAN-MINIMAL: error: invalid argument '-fsanitize-minimal-runtime' not allowed with '-fsanitize=thread' // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-MINIMAL -// CHECK-UBSAN-MINIMAL: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}} +// CHECK-UBSAN-MINIMAL: "-fsanitize={{((signed-integer-overflow|signed-integer-wrap|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){19}"}} // CHECK-UBSAN-MINIMAL: "-fsanitize-minimal-runtime" // RUN: %clang --target=x86_64-linux-gnu -fsanitize=integer -fsanitize-trap=integer %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INTSAN-TRAP -// CHECK-INTSAN-TRAP: "-fsanitize-trap=integer-divide-by-zero,shift-base,shift-exponent,signed-integer-overflow,unsigned-integer-overflow,unsigned-shift-base,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change" +// CHECK-INTSAN-TRAP: "-fsanitize-trap=integer-divide-by-zero,shift-base,shift-exponent,signed-integer-overflow,signed-integer-wrap,unsigned-integer-overflow,unsigned-shift-base,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change" // RUN: %clang --target=x86_64-linux-gnu -fsanitize=integer -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INTSAN-MINIMAL -// CHECK-INTSAN-MINIMAL: "-fsanitize=integer-divide-by-zero,shift-base,shift-exponent,signed-integer-overflow,unsigned-integer-overflow,unsigned-shift-base,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change" +// CHECK-INTSAN-MINIMAL: "-fsanitize=integer-divide-by-zero,shift-base,shift-exponent,signed-integer-overflow,signed-integer-wrap,unsigned-integer-overflow,unsigned-shift-base,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change" // CHECK-INTSAN-MINIMAL: "-fsanitize-minimal-runtime" // RUN: %clang --target=aarch64-linux-android -march=armv8-a+memtag -fsanitize=memtag -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MEMTAG-MINIMAL @@ -968,7 +970,7 @@ // RUN: not %clang --target=x86_64-sie-ps5 -fsanitize=kcfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-KCFI // RUN: not %clang --target=x86_64-sie-ps5 -fsanitize=function -fsanitize=kcfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-KCFI --check-prefix=CHECK-UBSAN-FUNCTION // RUN: %clang --target=x86_64-sie-ps5 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-UNDEFINED -// CHECK-UBSAN-UNDEFINED: "-fsanitize={{((alignment|array-bounds|bool|builtin|enum|float-cast-overflow|integer-divide-by-zero|nonnull-attribute|null|pointer-overflow|return|returns-nonnull-attribute|shift-base|shift-exponent|signed-integer-overflow|unreachable|vla-bound),?){17}"}} +// CHECK-UBSAN-UNDEFINED: "-fsanitize={{((alignment|array-bounds|bool|builtin|enum|float-cast-overflow|integer-divide-by-zero|nonnull-attribute|null|pointer-overflow|return|returns-nonnull-attribute|shift-base|shift-exponent|signed-integer-overflow|signed-integer-wrap|unreachable|vla-bound),?){18}"}} // RUN: not %clang --target=armv6t2-eabi -mexecute-only -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION // RUN: not %clang --target=armv6t2-eabi -mexecute-only -fsanitize=kcfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-KCFI @@ -976,7 +978,7 @@ // CHECK-UBSAN-KCFI-DAG: error: invalid argument '-fsanitize=kcfi' not allowed with {{('x86_64-sie-ps5'|'armv6t2-unknown-unknown-eabi')}} // CHECK-UBSAN-FUNCTION-DAG: error: invalid argument '-fsanitize=function' not allowed with {{('x86_64-sie-ps5'|'armv6t2-unknown-unknown-eabi')}} -// CHECK-UBSAN-UNDEFINED-VPTR: "-fsanitize={{((alignment|array-bounds|bool|builtin|enum|float-cast-overflow|integer-divide-by-zero|nonnull-attribute|null|pointer-overflow|return|returns-nonnull-attribute|shift-base|shift-exponent|signed-integer-overflow|unreachable|vla-bound|vptr),?){18}"}} +// CHECK-UBSAN-UNDEFINED-VPTR: "-fsanitize={{((alignment|array-bounds|bool|builtin|enum|float-cast-overflow|integer-divide-by-zero|nonnull-attribute|null|pointer-overflow|return|returns-nonnull-attribute|shift-base|shift-exponent|signed-integer-overflow|signed-integer-wrap|unreachable|vla-bound|vptr),?){19}"}} // * Test BareMetal toolchain sanitizer support * >From 77732cb7a4a64c9794a82f86e2a2cfb4194e5c76 Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Wed, 31 Jan 2024 00:45:39 +0000 Subject: [PATCH 3/8] add codegen tests --- clang/test/CodeGen/integer-wrap.c | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 clang/test/CodeGen/integer-wrap.c diff --git a/clang/test/CodeGen/integer-wrap.c b/clang/test/CodeGen/integer-wrap.c new file mode 100644 index 00000000000000..b0a99e9becaa8b --- /dev/null +++ b/clang/test/CodeGen/integer-wrap.c @@ -0,0 +1,66 @@ +// Check that -fsanitize=signed-integer-wrap instruments with -fwrapv +// RUN: %clang_cc1 -fwrapv -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=signed-integer-wrap | FileCheck %s --check-prefix=CHECK + +// Check that -fsanitize=signed-integer-overflow doesn't instrument with -fwrapv +// RUN: %clang_cc1 -fwrapv -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=signed-integer-overflow | FileCheck %s --check-prefix=CHECKSIO + +extern volatile int a, b, c; + +// CHECK-LABEL: define void @test_add_overflow +void test_add_overflow(void) { + // CHECK: [[ADD0:%.*]] = load {{.*}} i32 + // CHECK-NEXT: [[ADD1:%.*]] = load {{.*}} i32 + // CHECK-NEXT: {{%.*}} = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[ADD0]], i32 [[ADD1]]) + // CHECK: call void @__ubsan_handle_add_overflow + + // CHECKSIO-NOT: call void @__ubsan_handle_add_overflow + a = b + c; +} + +// CHECK-LABEL: define void @test_inc_overflow +void test_inc_overflow(void) { + // This decays and gets handled by __ubsan_handle_add_overflow... + // CHECK: [[INC0:%.*]] = load {{.*}} i32 + // CHECK-NEXT: call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[INC0]], i32 1) + // CHECK: br {{.*}} %handler.add_overflow + + // CHECKSIO-NOT: br {{.*}} %handler.add_overflow + ++a; + a++; +} + +// CHECK-LABEL: define void @test_sub_overflow +void test_sub_overflow(void) { + // CHECK: [[SUB0:%.*]] = load {{.*}} i32 + // CHECK-NEXT: [[SUB1:%.*]] = load {{.*}} i32 + // CHECK-NEXT: call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[SUB0]], i32 [[SUB1]]) + // CHECK: call void @__ubsan_handle_sub_overflow + + // CHECKSIO-NOT: call void @__ubsan_handle_sub_overflow + a = b - c; +} + +// CHECK-LABEL: define void @test_mul_overflow +void test_mul_overflow(void) { + // CHECK: [[MUL0:%.*]] = load {{.*}} i32 + // CHECK-NEXT: [[MUL1:%.*]] = load {{.*}} i32 + // CHECK-NEXT: call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[MUL0]], i32 [[MUL1]]) + // CHECK: call void @__ubsan_handle_mul_overflow + + // CHECKSIO-NOT: call void @__ubsan_handle_mul_overflow + a = b * c; +} + +// CHECK-LABEL: define void @test_div_overflow +void test_div_overflow(void) { + // CHECK: [[DIV0:%.*]] = load {{.*}} i32 + // CHECK-NEXT: [[DIV1:%.*]] = load {{.*}} i32 + // CHECK-NEXT: [[DIV2:%.*]] = icmp ne i32 [[DIV0]], -2147483648 + // CHECK-NEXT: [[DIV3:%.*]] = icmp ne i32 [[DIV1]], -1 + // CHECK-NEXT: [[DIVOR:%or]] = or i1 [[DIV2]], [[DIV3]] + // CHECK-NEXT: br {{.*}} %handler.divrem_overflow + + // -fsanitize=signed-integer-overflow still instruments division even with -fwrapv + // CHECKSIO: br {{.*}} %handler.divrem_overflow + a = b / c; +} >From d9d773728969789a7eae93a31d8b12b33659f424 Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Wed, 31 Jan 2024 20:54:03 +0000 Subject: [PATCH 4/8] run clang-format --- clang/lib/CodeGen/CGExprScalar.cpp | 20 ++++++++++---------- compiler-rt/lib/ubsan/ubsan_checks.inc | 3 +-- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 5c05a0d7524244..292db92ffa2a82 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -3429,7 +3429,7 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( const auto *BO = cast<BinaryOperator>(Ops.E); if (CGF.SanOpts.hasOneOf(SanitizerKind::SignedIntegerOverflow | - SanitizerKind::SignedIntegerWrap) && + SanitizerKind::SignedIntegerWrap) && Ops.Ty->hasSignedIntegerRepresentation() && !IsWidenedIntegerOp(CGF.getContext(), BO->getLHS()) && Ops.mayHaveIntegerOverflow()) { @@ -3448,7 +3448,6 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( if (CGF.SanOpts.has(SanitizerKind::SignedIntegerWrap)) Checks.push_back( std::make_pair(NotOverflow, SanitizerKind::SignedIntegerWrap)); - } if (Checks.size() > 0) @@ -3459,8 +3458,8 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { { CodeGenFunction::SanitizerScope SanScope(&CGF); if (CGF.SanOpts.hasOneOf(SanitizerKind::IntegerDivideByZero | - SanitizerKind::SignedIntegerOverflow | - SanitizerKind::SignedIntegerWrap) && + SanitizerKind::SignedIntegerOverflow | + SanitizerKind::SignedIntegerWrap) && Ops.Ty->isIntegerType() && (Ops.mayHaveIntegerDivisionByZero() || Ops.mayHaveIntegerOverflow())) { llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty)); @@ -3509,8 +3508,8 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { // Rem in C can't be a floating point type: C99 6.5.5p2. if (CGF.SanOpts.hasOneOf(SanitizerKind::IntegerDivideByZero | - SanitizerKind::SignedIntegerOverflow | - SanitizerKind::SignedIntegerWrap) && + SanitizerKind::SignedIntegerOverflow | + SanitizerKind::SignedIntegerWrap) && Ops.Ty->isIntegerType() && (Ops.mayHaveIntegerDivisionByZero() || Ops.mayHaveIntegerOverflow())) { CodeGenFunction::SanitizerScope SanScope(&CGF); @@ -3575,15 +3574,16 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { // If the signed-integer-overflow or signed-integer-wrap sanitizer is // enabled, emit a call to its runtime. Otherwise, this is a -ftrapv check, // so just emit a trap. - if (!isSigned || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow) - || CGF.SanOpts.has(SanitizerKind::SignedIntegerWrap)) { + if (!isSigned || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow) || + CGF.SanOpts.has(SanitizerKind::SignedIntegerWrap)) { llvm::Value *NotOverflow = Builder.CreateNot(overflow); SanitizerMask Kind = SanitizerKind::UnsignedIntegerOverflow; if (isSigned) Kind = CGF.getLangOpts().getSignedOverflowBehavior() == - LangOptions::SOB_Defined ? SanitizerKind::SignedIntegerWrap : - SanitizerKind::SignedIntegerOverflow; + LangOptions::SOB_Defined + ? SanitizerKind::SignedIntegerWrap + : SanitizerKind::SignedIntegerOverflow; EmitBinOpCheck(std::make_pair(NotOverflow, Kind), Ops); } else diff --git a/compiler-rt/lib/ubsan/ubsan_checks.inc b/compiler-rt/lib/ubsan/ubsan_checks.inc index b50ba91a158284..0112aeeed3f8ea 100644 --- a/compiler-rt/lib/ubsan/ubsan_checks.inc +++ b/compiler-rt/lib/ubsan/ubsan_checks.inc @@ -31,8 +31,7 @@ UBSAN_CHECK(AlignmentAssumption, "alignment-assumption", "alignment") UBSAN_CHECK(InsufficientObjectSize, "insufficient-object-size", "object-size") UBSAN_CHECK(SignedIntegerOverflow, "signed-integer-overflow", "signed-integer-overflow") -UBSAN_CHECK(SignedIntegerWrap, "signed-integer-wrap", - "signed-integer-wrap") +UBSAN_CHECK(SignedIntegerWrap, "signed-integer-wrap", "signed-integer-wrap") UBSAN_CHECK(UnsignedIntegerOverflow, "unsigned-integer-overflow", "unsigned-integer-overflow") UBSAN_CHECK(IntegerDivideByZero, "integer-divide-by-zero", >From f00e6a34c2994d47501ab64768b31d44094afe62 Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Wed, 31 Jan 2024 21:22:37 +0000 Subject: [PATCH 5/8] check for overflow bit in codegen tests --- clang/test/CodeGen/integer-wrap.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/clang/test/CodeGen/integer-wrap.c b/clang/test/CodeGen/integer-wrap.c index b0a99e9becaa8b..b3d3f0072b04f1 100644 --- a/clang/test/CodeGen/integer-wrap.c +++ b/clang/test/CodeGen/integer-wrap.c @@ -10,7 +10,10 @@ extern volatile int a, b, c; void test_add_overflow(void) { // CHECK: [[ADD0:%.*]] = load {{.*}} i32 // CHECK-NEXT: [[ADD1:%.*]] = load {{.*}} i32 - // CHECK-NEXT: {{%.*}} = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[ADD0]], i32 [[ADD1]]) + // CHECK-NEXT: [[ADD2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[ADD0]], i32 [[ADD1]]) + // CHECK: [[ADD4:%.*]] = extractvalue { i32, i1 } [[ADD2]], 1 + // CHECK-NEXT: [[ADD5:%.*]] = xor i1 [[ADD4]], true + // CHECK-NEXT: br i1 [[ADD5]], {{.*}} %handler.add_overflow // CHECK: call void @__ubsan_handle_add_overflow // CHECKSIO-NOT: call void @__ubsan_handle_add_overflow @@ -21,11 +24,13 @@ void test_add_overflow(void) { void test_inc_overflow(void) { // This decays and gets handled by __ubsan_handle_add_overflow... // CHECK: [[INC0:%.*]] = load {{.*}} i32 - // CHECK-NEXT: call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[INC0]], i32 1) - // CHECK: br {{.*}} %handler.add_overflow + // CHECK-NEXT: [[INC1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[INC0]], i32 1) + // CHECK: [[INC3:%.*]] = extractvalue { i32, i1 } [[INC1]], 1 + // CHECK-NEXT: [[INC4:%.*]] = xor i1 [[INC3]], true + // CHECK-NEXT: br i1 [[INC4]], {{.*}} %handler.add_overflow + // CHECK: call void @__ubsan_handle_add_overflow - // CHECKSIO-NOT: br {{.*}} %handler.add_overflow - ++a; + // CHECKSIO-NOT: call void @__ubsan_handle_add_overflow a++; } @@ -33,7 +38,10 @@ void test_inc_overflow(void) { void test_sub_overflow(void) { // CHECK: [[SUB0:%.*]] = load {{.*}} i32 // CHECK-NEXT: [[SUB1:%.*]] = load {{.*}} i32 - // CHECK-NEXT: call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[SUB0]], i32 [[SUB1]]) + // CHECK-NEXT: [[SUB2:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[SUB0]], i32 [[SUB1]]) + // CHECK: [[SUB4:%.*]] = extractvalue { i32, i1 } [[SUB2]], 1 + // CHECK-NEXT: [[SUB5:%.*]] = xor i1 [[SUB4]], true + // CHECK-NEXT br i1 [[SUB5]], {{.*}} %handler.sub_overflow // CHECK: call void @__ubsan_handle_sub_overflow // CHECKSIO-NOT: call void @__ubsan_handle_sub_overflow @@ -44,7 +52,10 @@ void test_sub_overflow(void) { void test_mul_overflow(void) { // CHECK: [[MUL0:%.*]] = load {{.*}} i32 // CHECK-NEXT: [[MUL1:%.*]] = load {{.*}} i32 - // CHECK-NEXT: call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[MUL0]], i32 [[MUL1]]) + // CHECK-NEXT: [[MUL2:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[MUL0]], i32 [[MUL1]]) + // CHECK: [[MUL4:%.*]] = extractvalue { i32, i1 } [[MUL2]], 1 + // CHECK-NEXT [[MUL5:%.*]] = xor i1 [[MUL4]], true + // CHECK-NEXT br i1 [[MUL5]], {{.*}} %handler.mul_overflow // CHECK: call void @__ubsan_handle_mul_overflow // CHECKSIO-NOT: call void @__ubsan_handle_mul_overflow >From 01699c19afff110b135b6c69fc7d3ebefed856e9 Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Wed, 31 Jan 2024 21:53:28 +0000 Subject: [PATCH 6/8] prefer CHECK{SIW|SIO} to CHECK --- clang/test/CodeGen/integer-wrap.c | 72 +++++++++++++++---------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/clang/test/CodeGen/integer-wrap.c b/clang/test/CodeGen/integer-wrap.c index b3d3f0072b04f1..2ccf59d0777051 100644 --- a/clang/test/CodeGen/integer-wrap.c +++ b/clang/test/CodeGen/integer-wrap.c @@ -1,75 +1,75 @@ // Check that -fsanitize=signed-integer-wrap instruments with -fwrapv -// RUN: %clang_cc1 -fwrapv -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=signed-integer-wrap | FileCheck %s --check-prefix=CHECK +// RUN: %clang_cc1 -fwrapv -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=signed-integer-wrap | FileCheck %s --check-prefix=CHECKSIW // Check that -fsanitize=signed-integer-overflow doesn't instrument with -fwrapv // RUN: %clang_cc1 -fwrapv -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=signed-integer-overflow | FileCheck %s --check-prefix=CHECKSIO extern volatile int a, b, c; -// CHECK-LABEL: define void @test_add_overflow +// CHECKSIW-LABEL: define void @test_add_overflow void test_add_overflow(void) { - // CHECK: [[ADD0:%.*]] = load {{.*}} i32 - // CHECK-NEXT: [[ADD1:%.*]] = load {{.*}} i32 - // CHECK-NEXT: [[ADD2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[ADD0]], i32 [[ADD1]]) - // CHECK: [[ADD4:%.*]] = extractvalue { i32, i1 } [[ADD2]], 1 - // CHECK-NEXT: [[ADD5:%.*]] = xor i1 [[ADD4]], true - // CHECK-NEXT: br i1 [[ADD5]], {{.*}} %handler.add_overflow - // CHECK: call void @__ubsan_handle_add_overflow + // CHECKSIW: [[ADD0:%.*]] = load {{.*}} i32 + // CHECKSIW-NEXT: [[ADD1:%.*]] = load {{.*}} i32 + // CHECKSIW-NEXT: [[ADD2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[ADD0]], i32 [[ADD1]]) + // CHECKSIW: [[ADD4:%.*]] = extractvalue { i32, i1 } [[ADD2]], 1 + // CHECKSIW-NEXT: [[ADD5:%.*]] = xor i1 [[ADD4]], true + // CHECKSIW-NEXT: br i1 [[ADD5]], {{.*}} %handler.add_overflow + // CHECKSIW: call void @__ubsan_handle_add_overflow // CHECKSIO-NOT: call void @__ubsan_handle_add_overflow a = b + c; } -// CHECK-LABEL: define void @test_inc_overflow +// CHECKSIW-LABEL: define void @test_inc_overflow void test_inc_overflow(void) { // This decays and gets handled by __ubsan_handle_add_overflow... - // CHECK: [[INC0:%.*]] = load {{.*}} i32 - // CHECK-NEXT: [[INC1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[INC0]], i32 1) - // CHECK: [[INC3:%.*]] = extractvalue { i32, i1 } [[INC1]], 1 - // CHECK-NEXT: [[INC4:%.*]] = xor i1 [[INC3]], true - // CHECK-NEXT: br i1 [[INC4]], {{.*}} %handler.add_overflow - // CHECK: call void @__ubsan_handle_add_overflow + // CHECKSIW: [[INC0:%.*]] = load {{.*}} i32 + // CHECKSIW-NEXT: [[INC1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[INC0]], i32 1) + // CHECKSIW: [[INC3:%.*]] = extractvalue { i32, i1 } [[INC1]], 1 + // CHECKSIW-NEXT: [[INC4:%.*]] = xor i1 [[INC3]], true + // CHECKSIW-NEXT: br i1 [[INC4]], {{.*}} %handler.add_overflow + // CHECKSIW: call void @__ubsan_handle_add_overflow // CHECKSIO-NOT: call void @__ubsan_handle_add_overflow a++; } -// CHECK-LABEL: define void @test_sub_overflow +// CHECKSIW-LABEL: define void @test_sub_overflow void test_sub_overflow(void) { - // CHECK: [[SUB0:%.*]] = load {{.*}} i32 - // CHECK-NEXT: [[SUB1:%.*]] = load {{.*}} i32 - // CHECK-NEXT: [[SUB2:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[SUB0]], i32 [[SUB1]]) - // CHECK: [[SUB4:%.*]] = extractvalue { i32, i1 } [[SUB2]], 1 - // CHECK-NEXT: [[SUB5:%.*]] = xor i1 [[SUB4]], true + // CHECKSIW: [[SUB0:%.*]] = load {{.*}} i32 + // CHECKSIW-NEXT: [[SUB1:%.*]] = load {{.*}} i32 + // CHECKSIW-NEXT: [[SUB2:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[SUB0]], i32 [[SUB1]]) + // CHECKSIW: [[SUB4:%.*]] = extractvalue { i32, i1 } [[SUB2]], 1 + // CHECKSIW-NEXT: [[SUB5:%.*]] = xor i1 [[SUB4]], true // CHECK-NEXT br i1 [[SUB5]], {{.*}} %handler.sub_overflow - // CHECK: call void @__ubsan_handle_sub_overflow + // CHECKSIW: call void @__ubsan_handle_sub_overflow // CHECKSIO-NOT: call void @__ubsan_handle_sub_overflow a = b - c; } -// CHECK-LABEL: define void @test_mul_overflow +// CHECKSIW-LABEL: define void @test_mul_overflow void test_mul_overflow(void) { - // CHECK: [[MUL0:%.*]] = load {{.*}} i32 - // CHECK-NEXT: [[MUL1:%.*]] = load {{.*}} i32 - // CHECK-NEXT: [[MUL2:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[MUL0]], i32 [[MUL1]]) - // CHECK: [[MUL4:%.*]] = extractvalue { i32, i1 } [[MUL2]], 1 + // CHECKSIW: [[MUL0:%.*]] = load {{.*}} i32 + // CHECKSIW-NEXT: [[MUL1:%.*]] = load {{.*}} i32 + // CHECKSIW-NEXT: [[MUL2:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[MUL0]], i32 [[MUL1]]) + // CHECKSIW: [[MUL4:%.*]] = extractvalue { i32, i1 } [[MUL2]], 1 // CHECK-NEXT [[MUL5:%.*]] = xor i1 [[MUL4]], true // CHECK-NEXT br i1 [[MUL5]], {{.*}} %handler.mul_overflow - // CHECK: call void @__ubsan_handle_mul_overflow + // CHECKSIW: call void @__ubsan_handle_mul_overflow // CHECKSIO-NOT: call void @__ubsan_handle_mul_overflow a = b * c; } -// CHECK-LABEL: define void @test_div_overflow +// CHECKSIW-LABEL: define void @test_div_overflow void test_div_overflow(void) { - // CHECK: [[DIV0:%.*]] = load {{.*}} i32 - // CHECK-NEXT: [[DIV1:%.*]] = load {{.*}} i32 - // CHECK-NEXT: [[DIV2:%.*]] = icmp ne i32 [[DIV0]], -2147483648 - // CHECK-NEXT: [[DIV3:%.*]] = icmp ne i32 [[DIV1]], -1 - // CHECK-NEXT: [[DIVOR:%or]] = or i1 [[DIV2]], [[DIV3]] - // CHECK-NEXT: br {{.*}} %handler.divrem_overflow + // CHECKSIW: [[DIV0:%.*]] = load {{.*}} i32 + // CHECKSIW-NEXT: [[DIV1:%.*]] = load {{.*}} i32 + // CHECKSIW-NEXT: [[DIV2:%.*]] = icmp ne i32 [[DIV0]], -2147483648 + // CHECKSIW-NEXT: [[DIV3:%.*]] = icmp ne i32 [[DIV1]], -1 + // CHECKSIW-NEXT: [[DIVOR:%or]] = or i1 [[DIV2]], [[DIV3]] + // CHECKSIW-NEXT: br {{.*}} %handler.divrem_overflow // -fsanitize=signed-integer-overflow still instruments division even with -fwrapv // CHECKSIO: br {{.*}} %handler.divrem_overflow >From 5497e8bc6849bf64c1158ff16b4aa04fd9141920 Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Tue, 13 Feb 2024 22:41:54 +0000 Subject: [PATCH 7/8] move wrap tests to integer-overflow.c --- clang/test/CodeGen/integer-overflow.c | 32 +++++++---- clang/test/CodeGen/integer-wrap.c | 77 --------------------------- 2 files changed, 23 insertions(+), 86 deletions(-) delete mode 100644 clang/test/CodeGen/integer-wrap.c diff --git a/clang/test/CodeGen/integer-overflow.c b/clang/test/CodeGen/integer-overflow.c index 9a3107c0b52926..6f1a91840ab867 100644 --- a/clang/test/CodeGen/integer-overflow.c +++ b/clang/test/CodeGen/integer-overflow.c @@ -3,6 +3,8 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -ftrapv | FileCheck %s --check-prefix=TRAPV // RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fsanitize=signed-integer-overflow | FileCheck %s --check-prefix=CATCH_UB // RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -ftrapv -ftrapv-handler foo | FileCheck %s --check-prefix=TRAPV_HANDLER +// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fwrapv -fsanitize=signed-integer-wrap | FileCheck %s --check-prefix=CATCH_WRAP + // Tests for signed integer overflow stuff. @@ -11,51 +13,57 @@ void test1(void) { // WRAPV-LABEL: define{{.*}} void @test1 // TRAPV-LABEL: define{{.*}} void @test1 extern volatile int f11G, a, b; - + // DEFAULT: add nsw i32 // WRAPV: add i32 // TRAPV: llvm.sadd.with.overflow.i32 // CATCH_UB: llvm.sadd.with.overflow.i32 + // CATCH_WRAP: llvm.sadd.with.overflow.i32 // TRAPV_HANDLER: foo( f11G = a + b; - + // DEFAULT: sub nsw i32 // WRAPV: sub i32 // TRAPV: llvm.ssub.with.overflow.i32 // CATCH_UB: llvm.ssub.with.overflow.i32 + // CATCH_WRAP: llvm.ssub.with.overflow.i32 // TRAPV_HANDLER: foo( f11G = a - b; - + // DEFAULT: mul nsw i32 // WRAPV: mul i32 // TRAPV: llvm.smul.with.overflow.i32 // CATCH_UB: llvm.smul.with.overflow.i32 + // CATCH_WRAP: llvm.smul.with.overflow.i32 // TRAPV_HANDLER: foo( f11G = a * b; - // DEFAULT: sub nsw i32 0, - // WRAPV: sub i32 0, + // DEFAULT: sub nsw i32 0, + // WRAPV: sub i32 0, // TRAPV: llvm.ssub.with.overflow.i32(i32 0 // CATCH_UB: llvm.ssub.with.overflow.i32(i32 0 + // CATCH_WRAP: llvm.ssub.with.overflow.i32(i32 0 // TRAPV_HANDLER: foo( f11G = -a; - + // PR7426 - Overflow checking for increments. - + // DEFAULT: add nsw i32 {{.*}}, 1 // WRAPV: add i32 {{.*}}, 1 // TRAPV: llvm.sadd.with.overflow.i32({{.*}}, i32 1) // CATCH_UB: llvm.sadd.with.overflow.i32({{.*}}, i32 1) + // CATCH_WRAP: llvm.sadd.with.overflow.i32({{.*}}, i32 1) // TRAPV_HANDLER: foo( ++a; - + // DEFAULT: add nsw i32 {{.*}}, -1 // WRAPV: add i32 {{.*}}, -1 // TRAPV: llvm.ssub.with.overflow.i32({{.*}}, i32 1) // CATCH_UB: llvm.ssub.with.overflow.i32({{.*}}, i32 1) + // CATCH_WRAP: llvm.ssub.with.overflow.i32({{.*}}, i32 1) // TRAPV_HANDLER: foo( --a; - + // -fwrapv should turn off inbounds for GEP's, PR9256 extern int* P; ++P; @@ -63,6 +71,7 @@ void test1(void) { // WRAPV: getelementptr i32, ptr // TRAPV: getelementptr inbounds i32, ptr // CATCH_UB: getelementptr inbounds i32, ptr + // CATCH_WRAP: getelementptr i32, ptr // PR9350: char pre-increment never overflows. extern volatile signed char PR9350_char_inc; @@ -70,6 +79,7 @@ void test1(void) { // WRAPV: add i8 {{.*}}, 1 // TRAPV: add i8 {{.*}}, 1 // CATCH_UB: add i8 {{.*}}, 1 + // CATCH_WRAP: add i8 {{.*}}, 1 ++PR9350_char_inc; // PR9350: char pre-decrement never overflows. @@ -78,6 +88,7 @@ void test1(void) { // WRAPV: add i8 {{.*}}, -1 // TRAPV: add i8 {{.*}}, -1 // CATCH_UB: add i8 {{.*}}, -1 + // CATCH_WRAP: add i8 {{.*}}, -1 --PR9350_char_dec; // PR9350: short pre-increment never overflows. @@ -86,6 +97,7 @@ void test1(void) { // WRAPV: add i16 {{.*}}, 1 // TRAPV: add i16 {{.*}}, 1 // CATCH_UB: add i16 {{.*}}, 1 + // CATCH_WRAP: add i16 {{.*}}, 1 ++PR9350_short_inc; // PR9350: short pre-decrement never overflows. @@ -94,6 +106,7 @@ void test1(void) { // WRAPV: add i16 {{.*}}, -1 // TRAPV: add i16 {{.*}}, -1 // CATCH_UB: add i16 {{.*}}, -1 + // CATCH_WRAP: add i16 {{.*}}, -1 --PR9350_short_dec; // PR24256: don't instrument __builtin_frame_address. @@ -102,4 +115,5 @@ void test1(void) { // WRAPV: call ptr @llvm.frameaddress.p0(i32 0) // TRAPV: call ptr @llvm.frameaddress.p0(i32 0) // CATCH_UB: call ptr @llvm.frameaddress.p0(i32 0) + // CATCH_WRAP: call ptr @llvm.frameaddress.p0(i32 0) } diff --git a/clang/test/CodeGen/integer-wrap.c b/clang/test/CodeGen/integer-wrap.c deleted file mode 100644 index 2ccf59d0777051..00000000000000 --- a/clang/test/CodeGen/integer-wrap.c +++ /dev/null @@ -1,77 +0,0 @@ -// Check that -fsanitize=signed-integer-wrap instruments with -fwrapv -// RUN: %clang_cc1 -fwrapv -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=signed-integer-wrap | FileCheck %s --check-prefix=CHECKSIW - -// Check that -fsanitize=signed-integer-overflow doesn't instrument with -fwrapv -// RUN: %clang_cc1 -fwrapv -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=signed-integer-overflow | FileCheck %s --check-prefix=CHECKSIO - -extern volatile int a, b, c; - -// CHECKSIW-LABEL: define void @test_add_overflow -void test_add_overflow(void) { - // CHECKSIW: [[ADD0:%.*]] = load {{.*}} i32 - // CHECKSIW-NEXT: [[ADD1:%.*]] = load {{.*}} i32 - // CHECKSIW-NEXT: [[ADD2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[ADD0]], i32 [[ADD1]]) - // CHECKSIW: [[ADD4:%.*]] = extractvalue { i32, i1 } [[ADD2]], 1 - // CHECKSIW-NEXT: [[ADD5:%.*]] = xor i1 [[ADD4]], true - // CHECKSIW-NEXT: br i1 [[ADD5]], {{.*}} %handler.add_overflow - // CHECKSIW: call void @__ubsan_handle_add_overflow - - // CHECKSIO-NOT: call void @__ubsan_handle_add_overflow - a = b + c; -} - -// CHECKSIW-LABEL: define void @test_inc_overflow -void test_inc_overflow(void) { - // This decays and gets handled by __ubsan_handle_add_overflow... - // CHECKSIW: [[INC0:%.*]] = load {{.*}} i32 - // CHECKSIW-NEXT: [[INC1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[INC0]], i32 1) - // CHECKSIW: [[INC3:%.*]] = extractvalue { i32, i1 } [[INC1]], 1 - // CHECKSIW-NEXT: [[INC4:%.*]] = xor i1 [[INC3]], true - // CHECKSIW-NEXT: br i1 [[INC4]], {{.*}} %handler.add_overflow - // CHECKSIW: call void @__ubsan_handle_add_overflow - - // CHECKSIO-NOT: call void @__ubsan_handle_add_overflow - a++; -} - -// CHECKSIW-LABEL: define void @test_sub_overflow -void test_sub_overflow(void) { - // CHECKSIW: [[SUB0:%.*]] = load {{.*}} i32 - // CHECKSIW-NEXT: [[SUB1:%.*]] = load {{.*}} i32 - // CHECKSIW-NEXT: [[SUB2:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[SUB0]], i32 [[SUB1]]) - // CHECKSIW: [[SUB4:%.*]] = extractvalue { i32, i1 } [[SUB2]], 1 - // CHECKSIW-NEXT: [[SUB5:%.*]] = xor i1 [[SUB4]], true - // CHECK-NEXT br i1 [[SUB5]], {{.*}} %handler.sub_overflow - // CHECKSIW: call void @__ubsan_handle_sub_overflow - - // CHECKSIO-NOT: call void @__ubsan_handle_sub_overflow - a = b - c; -} - -// CHECKSIW-LABEL: define void @test_mul_overflow -void test_mul_overflow(void) { - // CHECKSIW: [[MUL0:%.*]] = load {{.*}} i32 - // CHECKSIW-NEXT: [[MUL1:%.*]] = load {{.*}} i32 - // CHECKSIW-NEXT: [[MUL2:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[MUL0]], i32 [[MUL1]]) - // CHECKSIW: [[MUL4:%.*]] = extractvalue { i32, i1 } [[MUL2]], 1 - // CHECK-NEXT [[MUL5:%.*]] = xor i1 [[MUL4]], true - // CHECK-NEXT br i1 [[MUL5]], {{.*}} %handler.mul_overflow - // CHECKSIW: call void @__ubsan_handle_mul_overflow - - // CHECKSIO-NOT: call void @__ubsan_handle_mul_overflow - a = b * c; -} - -// CHECKSIW-LABEL: define void @test_div_overflow -void test_div_overflow(void) { - // CHECKSIW: [[DIV0:%.*]] = load {{.*}} i32 - // CHECKSIW-NEXT: [[DIV1:%.*]] = load {{.*}} i32 - // CHECKSIW-NEXT: [[DIV2:%.*]] = icmp ne i32 [[DIV0]], -2147483648 - // CHECKSIW-NEXT: [[DIV3:%.*]] = icmp ne i32 [[DIV1]], -1 - // CHECKSIW-NEXT: [[DIVOR:%or]] = or i1 [[DIV2]], [[DIV3]] - // CHECKSIW-NEXT: br {{.*}} %handler.divrem_overflow - - // -fsanitize=signed-integer-overflow still instruments division even with -fwrapv - // CHECKSIO: br {{.*}} %handler.divrem_overflow - a = b / c; -} >From e96443184c6059ab8c5b97badc9ecc7270d4d466 Mon Sep 17 00:00:00 2001 From: Justin Stitt <justinst...@google.com> Date: Tue, 13 Feb 2024 22:47:32 +0000 Subject: [PATCH 8/8] prefer hasOneOf() over multiple has() --- clang/lib/CodeGen/CGExprScalar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 292db92ffa2a82..eb3d0b60a29a01 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -3574,8 +3574,8 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { // If the signed-integer-overflow or signed-integer-wrap sanitizer is // enabled, emit a call to its runtime. Otherwise, this is a -ftrapv check, // so just emit a trap. - if (!isSigned || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow) || - CGF.SanOpts.has(SanitizerKind::SignedIntegerWrap)) { + if (!isSigned || CGF.SanOpts.hasOneOf(SanitizerKind::SignedIntegerOverflow | + SanitizerKind::SignedIntegerWrap)) { llvm::Value *NotOverflow = Builder.CreateNot(overflow); SanitizerMask Kind = SanitizerKind::UnsignedIntegerOverflow; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits