[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
Justin Stitt via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 13 15:26:42 PST 2024
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 <justinstitt at google.com>
Date: Tue, 23 Jan 2024 23:28:42 +0000
Subject: [PATCH 1/9] 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 <justinstitt at google.com>
Date: Tue, 30 Jan 2024 22:21:10 +0000
Subject: [PATCH 2/9] 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 <justinstitt at google.com>
Date: Wed, 31 Jan 2024 00:45:39 +0000
Subject: [PATCH 3/9] 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 <justinstitt at google.com>
Date: Wed, 31 Jan 2024 20:54:03 +0000
Subject: [PATCH 4/9] 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 <justinstitt at google.com>
Date: Wed, 31 Jan 2024 21:22:37 +0000
Subject: [PATCH 5/9] 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 <justinstitt at google.com>
Date: Wed, 31 Jan 2024 21:53:28 +0000
Subject: [PATCH 6/9] 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 <justinstitt at google.com>
Date: Tue, 13 Feb 2024 22:41:54 +0000
Subject: [PATCH 7/9] 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 <justinstitt at google.com>
Date: Tue, 13 Feb 2024 22:47:32 +0000
Subject: [PATCH 8/9] 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;
>From e15b6e636c27d00a4ef8d0a0f8f648bdcf11d44b Mon Sep 17 00:00:00 2001
From: Justin Stitt <justinstitt at google.com>
Date: Tue, 13 Feb 2024 23:26:04 +0000
Subject: [PATCH 9/9] add docs for signed-integer-wrap
---
clang/docs/UndefinedBehaviorSanitizer.rst | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/clang/docs/UndefinedBehaviorSanitizer.rst b/clang/docs/UndefinedBehaviorSanitizer.rst
index b8ad3804f18903..25640b4a584380 100644
--- a/clang/docs/UndefinedBehaviorSanitizer.rst
+++ b/clang/docs/UndefinedBehaviorSanitizer.rst
@@ -193,7 +193,14 @@ Available checks are:
signed division overflow (``INT_MIN/-1``), but not checks for
lossy implicit conversions performed before the computation
(see ``-fsanitize=implicit-conversion``). Both of these two issues are
- handled by ``-fsanitize=implicit-conversion`` group of checks.
+ handled by ``-fsanitize=implicit-conversion`` group of checks. Note that
+ ``-fwrapv`` implicitly disables instrumentation for much of the arithmetic
+ covered by ``-fsanitize=signed-integer-overflow``.
+ - ``-fsanitize=signed-integer-wrap``: Signed Integer wraparound, where the
+ result of a signed integer computation wraps around. Behaves identically
+ to ``-fsanitize=signed-integer-overflow`` when ``-fwrapv`` is enabled.
+ Without ``-fwrapv`` or ``-fno-strict-overflow``, this sanitizer will only
+ instrument division operations.
- ``-fsanitize=unreachable``: If control flow reaches an unreachable
program point.
- ``-fsanitize=unsigned-integer-overflow``: Unsigned integer overflow, where
More information about the cfe-commits
mailing list