Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Sanitizer] add signed-integer-wrap sanitizer #80089

Closed
wants to merge 11 commits into from

Conversation

JustinStitt
Copy link
Contributor

@JustinStitt JustinStitt commented Jan 31, 2024

Reasoning
Clang has a signed-integer-overflow sanitizer to catch arithmetic overflow; however, most* of its instrumentation fails to apply when -fwrapv is enabled.

The Linux kernel enables -fno-strict-overflow which implies -fwrapv. This means we are currently unable to detect signed-integer wrap-around. All the while, the root cause of many security vulnerabilities in the Linux kernel is arithmetic overflow

In short, we need a way to instrument signed arithmetic even when the overflow behavior is technically defined due to -fwrapv. I propose we name the sanitizer "signed-integer-wrap" as it best captures the language semantics at hand.

* it seems division and modulo arithmetic is still instrumented with -fsanitize=signed-integer-overflow and -fwrapv

Other Notes

  • The unsigned-integer-overflow sanitizer is probably named incorrectly because "a computation involving unsigned operands can never overflow" 1.

  • Perhaps this sanitizer does not belong in the Undefined Behavior Sanitizer as wrap-around is not UB (although the instrumentation is exactly the same).

  • I tried running clang-format but the diff was huge and beyond just my changes. (fixed in 46ef570)

cc: @nickdesaulniers @kees @nathanchance @bwendling

Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be
notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write
permissions for the repository. In which case you can instead tag reviewers by
name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review
by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate
is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added clang Clang issues not falling into any other category compiler-rt clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen compiler-rt:sanitizer labels Jan 31, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Jan 31, 2024

@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-clang
@llvm/pr-subscribers-clang-driver

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Justin Stitt (JustinStitt)

Changes

Reasoning
Clang has a signed-integer-overflow sanitizer to catch arithmetic overflow; however, most* of its instrumentation fails to apply when -fwrapv is enabled.

The kernel enables -fno-strict-overflow which implies -fwrapv. This means we are currently unable to detect signed-integer wrap-around. All the while, the root cause of many security vulnerabilities in the Linux kernel is arithmetic overflow

In short, we need a way to instrument signed arithmetic even when the overflow behavior is technically defined due to -fwrapv. I propose we name the sanitizer "signed-integer-wrap" as it best captures the language semantics at hand.

* it seems division and modulo arithmetic is still instrumented with -fsanitize=signed-integer-overflow and -fwrapv

Other Notes

  • The unsigned-integer-overflow sanitizer is probably named incorrectly because "a computation involving unsigned operands can never overflow" 1.

  • Perhaps this sanitizer does not belong in the Undefined Behavior Sanitizer as wrap-around is not UB (although the instrumentation is exactly the same).

  • I tried running clang-format but the diff was huge and beyond just my changes.

cc: @nickdesaulniers @kees @nathanchance @bwendling


Patch is 28.27 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/80089.diff

5 Files Affected:

  • (modified) clang/include/clang/Basic/Sanitizers.def (+3-2)
  • (modified) clang/lib/CodeGen/CGExprScalar.cpp (+49-13)
  • (added) clang/test/CodeGen/integer-wrap.c (+66)
  • (modified) clang/test/Driver/fsanitize.c (+18-16)
  • (modified) compiler-rt/lib/ubsan/ubsan_checks.inc (+2)
diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def
index c2137e3f61f64..b987b26f93c39 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 5502f685f6474..74e016fe4899f 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))
@@ -2517,6 +2522,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))
@@ -3410,7 +3421,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),
@@ -3418,7 +3429,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()) {
@@ -3431,8 +3443,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)
@@ -3442,8 +3459,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));
@@ -3491,8 +3509,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);
@@ -3554,12 +3573,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);
@@ -3862,6 +3888,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))
@@ -4016,6 +4047,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/clang/test/CodeGen/integer-wrap.c b/clang/test/CodeGen/integer-wrap.c
new file mode 100644
index 0000000000000..b0a99e9becaa8
--- /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;
+}
diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c
index 1671825042c32..86172febf4723 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}"}...
[truncated]

Copy link

github-actions bot commented Jan 31, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@DavidSpickett
Copy link
Collaborator

I tried running clang-format but the diff was huge and beyond just my changes.

https://clang.llvm.org/docs/ClangFormat.html#git-integration tells you how to narrow it down to just your changes. Once that's setup you can use the command from the comment the bot left.

Sometimes it will try to format too much, in which case it's fine to ignore it, but looking at what the bot reported here that's not the case.

@nickdesaulniers
Copy link
Member

I tried running clang-format but the diff was huge and beyond just my changes.

I usually do git clang-format HEAD~N where N is the number of commits of mine (N is optional when N == 1).

@llvmbot llvmbot added the compiler-rt:ubsan Undefined behavior sanitizer label Jan 31, 2024
@JustinStitt
Copy link
Contributor Author

JustinStitt commented Jan 31, 2024

Hey, does anyone know why the CI bot (buildkite) fails my builds for a trailing whitespace in a file I did not touch?

It says there's some trailing whitespace in some documentation files that my PR doesn't touch (unless I'm misinterpreting its output):
https://buildkite.com/llvm-project/clang-ci/builds/11179#018d6167-a058-43d4-9d2e-6dbd9410a41a

edit: resolved. the build bot just builds the tree as it appears and doesn't patch my changeset onto a known working tree; the red build isn't my fault -- right?

clang/test/CodeGen/integer-wrap.c Outdated Show resolved Hide resolved
clang/test/CodeGen/integer-wrap.c Outdated Show resolved Hide resolved
@kees
Copy link
Contributor

kees commented Feb 1, 2024

Hey, does anyone know why the CI bot (buildkite) fails my builds for a trailing whitespace in a file I did not touch?

It says there's some trailing whitespace in some documentation files that my PR doesn't touch (unless I'm misinterpreting its output): https://buildkite.com/llvm-project/clang-ci/builds/11179#018d6167-a058-43d4-9d2e-6dbd9410a41a

That's mostly just bad luck. It's been fixed now, though, in commit 0217d2e so it should pass correctly now.

@JustinStitt
Copy link
Contributor Author

ping!

@kees
Copy link
Contributor

kees commented Feb 13, 2024

I've tested this with the Linux kernel, and it is working as expected. It is ready and waiting for this option to gain back a bunch of sanitizer coverage for CIs and likely in production kernels. :)

Copy link
Member

@nickdesaulniers nickdesaulniers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PATCH mostly LGTM

UBSan is documented clang/docs/UndefinedBehaviorSanitizer.rst https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html

Please make sure to update the list of available checks.

Please also update the release notes to mention this feature.
clang/docs/ReleaseNotes.rst

The kernel enables -fno-strict-overflow which implies -fwrapv.

While Linux is the only kernel I've contributed to, it's important to be explicit as to which kernel you're referring to. 😛

and likely in production kernels. :)

I doubt you meant running in production. 😛

clang/lib/CodeGen/CGExprScalar.cpp Outdated Show resolved Hide resolved
clang/test/CodeGen/integer-wrap.c Outdated Show resolved Hide resolved
clang/test/CodeGen/integer-wrap.c Outdated Show resolved Hide resolved
@kees
Copy link
Contributor

kees commented Feb 13, 2024

and likely in production kernels. :)

I doubt you meant running in production. 😛

I very much do -- I expect to use this like we use the array-bounds sanitizer, which is on in production in at least Ubuntu and Android. It may be a long road to getting sane coverage without endless false positives, of course. But the intent is to use it in production.

Copy link
Member

@nickdesaulniers nickdesaulniers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this patch is good to go. Thanks for working on it!

cc @AaronBallman @efriedma-quic @rjmccall @nikic in case there's any last minute concerns. I'm happy to sign off on this, but consider giving folks some time to speak up before landing this.

@JustinStitt
Copy link
Contributor Author

I think this patch is good to go. Thanks for working on it!

Thanks for the review Nick! BTW, I forgot to update the ReleaseNotes.rst, I've done so now (hopefully not voiding your previous review)

@AaronBallman
Copy link
Collaborator

I think this patch is good to go. Thanks for working on it!

cc @AaronBallman @efriedma-quic @rjmccall @nikic in case there's any last minute concerns. I'm happy to sign off on this, but consider giving folks some time to speak up before landing this.

No concerns from me, thanks!

Copy link
Contributor

@rjmccall rjmccall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, LGTM.

@vitalybuka
Copy link
Collaborator

Why not just enforce -fsanitize=signed-integer-overflow with -fwrapv? I suspect it's just overlook, and not intentional behavior.

@MaskRay
Copy link
Member

MaskRay commented Feb 14, 2024

Why not just enforce -fsanitize=signed-integer-overflow with -fwrapv? I suspect it's just overlook, and not intentional behavior.

+1

We should consider this direction

@kees
Copy link
Contributor

kees commented Feb 14, 2024

Why not just enforce -fsanitize=signed-integer-overflow with -fwrapv? I suspect it's just overlook, and not intentional behavior.

+1

We should consider this direction

The UB-vs-non-UB seemed to be a really specific goal in the existing code. i.e. that the sanitizer was disabled didn't look like an accident. For people using this to find only UB, this would be a behavioral change, so to me it seems like a separate name makes the most sense. Anyone wanting wrap-around checking can use -wrap, and anyone wanting UB checking can use -overflow.

@vitalybuka
Copy link
Collaborator

Why not just enforce -fsanitize=signed-integer-overflow with -fwrapv? I suspect it's just overlook, and not intentional behavior.

+1
We should consider this direction

The UB-vs-non-UB seemed to be a really specific goal in the existing code. i.e. that the sanitizer was disabled didn't look like an accident. For people using this to find only UB, this would be a behavioral change, so to me it seems like a separate name makes the most sense. Anyone wanting wrap-around checking can use -wrap, and anyone wanting UB checking can use -overflow.

Isn't this still UB even with -fwrapv? UB is a language feature, not compiler.

@vitalybuka
Copy link
Collaborator

signed-integer-overflow

Or maybe I am missing the bigger picture? Is there a plan fix signed-integer-overflow for -fwrapv as well?

@rjmccall
Copy link
Contributor

Why not just enforce -fsanitize=signed-integer-overflow with -fwrapv? I suspect it's just overlook, and not intentional behavior.

+1
We should consider this direction

The UB-vs-non-UB seemed to be a really specific goal in the existing code. i.e. that the sanitizer was disabled didn't look like an accident. For people using this to find only UB, this would be a behavioral change, so to me it seems like a separate name makes the most sense. Anyone wanting wrap-around checking can use -wrap, and anyone wanting UB checking can use -overflow.

Isn't this still UB even with -fwrapv? UB is a language feature, not compiler.

-fwrapv is essentially a language dialect that defines the behavior of integer wraparound. It is no longer UB in compilations using that mode.

@kees
Copy link
Contributor

kees commented Feb 14, 2024

Why not just enforce -fsanitize=signed-integer-overflow with -fwrapv? I suspect it's just overlook, and not intentional behavior.

+1
We should consider this direction

The UB-vs-non-UB seemed to be a really specific goal in the existing code. i.e. that the sanitizer was disabled didn't look like an accident. For people using this to find only UB, this would be a behavioral change, so to me it seems like a separate name makes the most sense. Anyone wanting wrap-around checking can use -wrap, and anyone wanting UB checking can use -overflow.

Isn't this still UB even with -fwrapv? UB is a language feature, not compiler.

-fwrapv is essentially a language dialect that defines the behavior of integer wraparound. It is no longer UB in compilations using that mode.

Right. -fwrapv defines the signed integer overflow resolution strategy. Without -fwrapv it is undefined (default language feature). With -fwrapv it is defined as 2s-complement wrap-around (and is well defined, like unsigned integer overflow).

@MaskRay
Copy link
Member

MaskRay commented Feb 15, 2024

This is a UI discussion about how command line options should behave.
Some folks prefer simpler rules while some prefer smart rules (guessing user intention).

A -fwrapv user may either:

  • rely on the wraparound behavior
  • or prevent certain optimizations that would raise security concerns

Our -fsanitize=signed-integer-overflow design have been assuming that -fwrapv users don't need the check.
This PR suggests that an important user does want overflow checks and our guess has failed.
It seems very confusing to have two options doing the same thing.

https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html is clear that not all checks are undefined behavior in the standards.

Issues caught by this sanitizer are not undefined behavior, but are often unintentional.

Sure -fwrapv makes wraparound defined, but it doesn't prevent us from making -fsanitize=signed-integer-overflow useful. "-fwrapv => no signed-integer-overflow" is not a solid argument.

I think we can try making -fsanitize=signed-integer-overflow effective even when -fwrapv if specified.
-fsanitize=signed-integer-overflow is rare in the wild, probably rarer when combined with -fwrapv.

There is a precedent that -fsanitize=undefined enables different checks for different targets.
We could make -fsanitize=undefined not imply -fsanitize=signed-integer-overflow when -fwrapv is specified, if we do want to guess the user intention.
Personally I'd prefer moving away from such behaviors and be more orthogonal.

@kees
Copy link
Contributor

kees commented Feb 15, 2024

@kees
Copy link
Contributor

kees commented Feb 15, 2024

Sure -fwrapv makes wraparound defined, but it doesn't prevent us from making -fsanitize=signed-integer-overflow useful. "-fwrapv => no signed-integer-overflow" is not a solid argument.

I think we can try making -fsanitize=signed-integer-overflow effective even when -fwrapv if specified. -fsanitize=signed-integer-overflow is rare in the wild, probably rarer when combined with -fwrapv.
.

In earlier GCC discussions, it seemed very much like the -fsanitize=signed-integer-overflow was meant for UB only, but maybe I misunderstood. See replies leading up to this:
https://gcc.gnu.org/pipermail/gcc-patches/2023-September/630578.html

@JustinStitt
Copy link
Contributor Author

JustinStitt commented Feb 15, 2024

My original idea was to get the SIO sanitizer working with -fwrapv, the issue here even suggests it as a viable option. However, after seeing literal checks like:

case LangOptions::SOB_Undefined:
        if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))

... I think the best option is to implement a wrap sanitizer (which this PR does). A wrap sanitizer best captures the language semantics at hand while maintaining existing functionality of the SIO sanitizer. I think Kees can speak first hand about how picky some folks are about the language being used for this arithmetic overflow/wraparound stuff (he linked some gcc threads above my comment but I've also seen some spicy LKML discussions about how OVERFLOW doesn't exist in the Linux Kernel and as such WRAPAROUND instrumentation is needed).

I think this PR bridges the gap between folks like Kees (who just want all this suspicious kernel arithmetic to go away) and folks like Linus (who is really particular about language).

@kees
Copy link
Contributor

kees commented Feb 20, 2024

GCC folks have not answered. Adding -wrap keeps the behavior for -overflow the same between GCC and Clang. Can we please move this forward and land it as is? We can trivially change this in the future if we need to.

@MaskRay
Copy link
Member

MaskRay commented Feb 20, 2024

GCC folks have not answered. Adding -wrap keeps the behavior for -overflow the same between GCC and Clang. Can we please move this forward and land it as is? We can trivially change this in the future if we need to.

I believe we can move forward by reusing -fsanitize=signed-integer-overflow, which adds least complexity to Clang and is very reasonable.

Copy link
Member

@MaskRay MaskRay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.

@JustinStitt
Copy link
Contributor Author

I believe we can move forward by reusing -fsanitize=signed-integer-overflow, which adds least complexity to Clang and is very reasonable.

I see a few problems with changing -fsanitize=signed-integer-overflow:

  1. Clang no longer matches GCC's SIO functionality

  2. Existing codebases (albeit, very few) may be affected by what is essentially a breaking change.

  3. The C spec language semantics all hint at signed-integer-overflow being a misnomer for the properties of the arithmetic we are sanitizing when -fwrapv is enabled. (really, unsigned-integer-overflow is also poorly named as unsigned arithmetic can't overflow 6.2.5.9)

Should a compiler not at least put some effort into properly representing the semantics at hand?

@MaskRay, there's been lots of good review on this PR with folks more or less liking the direction of it. I'd like to find some common ground on this so we can move it forward. If you really think changing the SIO sanitizer is the way to go I'll probably close this PR and open a new one as it represents a wholly different idea.

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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we refrase this differently?
Instead (or in addition) of reference to signed-integer-overflow, just explain that it will detect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the current version is not so clear. I must admit, though, I am not 100% sure what changes you would like. Vitaly, do you think it should be worded like such:

Note that ``-fwrapv`` implicitly disables most checks performed by this sanitizer 
as the overflow behavior is well-defined.

If this doesn't match what you were thinking could you let me know?

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.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? division looks like overflow to me?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it's very inconsistent that the sanitizer is less strict without -fwrapv, when for signed-integer-overflow we have an opposite.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going off the spec:

An implementation that defines signed integer types as also being modulo need not detect integer overflow, in which case, only integer divide-by-zero need be detected.

From H.2.2 Integer Types

I initially read this as meaning we need to instrument division no matter what (just in case it's divide by zero or similar case). What is your interpretation?

I can add a check for the signed overflow behavior for the division steps -- if needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it's very inconsistent that the sanitizer is less strict without -fwrapv, when for signed-integer-overflow we have an opposite.

Yes, this proposed "wrap" sanitizer is less strict when nothing is defined as wrapping (i.e: missing -fwrapv). Should this not be the case?

In the same way, signed-integer-overflow is more strict without -fwrapv as things are overflowing and not wrapping.

@MaskRay
Copy link
Member

MaskRay commented Feb 20, 2024

I believe we can move forward by reusing -fsanitize=signed-integer-overflow, which adds least complexity to Clang and is very reasonable.

I see a few problems with changing -fsanitize=signed-integer-overflow:

  1. Clang no longer matches GCC's SIO functionality
  2. Existing codebases (albeit, very few) may be affected by what is essentially a breaking change.

Should a compiler not at least put some effort into properly representing the semantics at hand?

While I understand adding a new way (to do similar things instead of improving the existing feature) can be tempting, as it avoids "disrupting" current users,
it can lead to software bloat and increased complexity for everyone.
There would be more options for users to read,. Enhancement to one mode might not be ported to the other (similar) one.

I feel that "not breaking existing users" is sometimes exaggerated to argue for not improving an existing feature.
Frankly, we provide ways for users to unblock them. And in this case it seems quite trivial. Add -fno-sanitize=signed-integer-overflow or drop the positive option.

I noticed in CodeSearch that this BUILD.gn seems used quite a bit. The author seems aware that with overflow checks, -fwrapv would not make sense.

+    if (is_clang && !is_ubsan && !is_ubsan_security) {
+      cflags += [ "-fwrapv" ]
+    }
  1. The C spec language semantics all hint at signed-integer-overflow being a misnomer for the properties of the arithmetic we are sanitizing when -fwrapv is enabled. (really, unsigned-integer-overflow is also poorly named as unsigned arithmetic can't overflow 6.2.5.9)

If there are semantics improvement, unrelated to "let's not break users for -fwrapv", I think a new mode is still worth considering.
I haven't read this patch closely, but I believe the patch's intention is just to introduce a new mode working with -fwrapv for the Linux kernel, at the cost of Clang complexity.

@MaskRay, there's been lots of good review on this PR with folks more or less liking the direction of it. I'd like to find some common ground on this so we can move it forward. If you really think changing the SIO sanitizer is the way to go I'll probably close this PR and open a new one as it represents a wholly different idea.

I agree that a new PR could be useful.

@kees
Copy link
Contributor

kees commented Mar 8, 2024

With PR #82432 landed, this PR is redundant. Thanks for changing the option name! Closing...

@kees kees closed this Mar 8, 2024
MaskRay added a commit that referenced this pull request Mar 19, 2024
…w if -fwrapv (#85501)

Linux kernel uses -fwrapv to change signed integer overflows from
undefined behaviors to defined behaviors. However, the security folks
still want -fsanitize=signed-integer-overflow diagnostics. Their
intention can be expressed with -fwrapv
-fsanitize=signed-integer-overflow (#80089). This mode by default
reports recoverable errors while still making signed integer overflows
defined (most UBSan checks are recoverable by default: you get errors in
stderr, but the program is not halted).

-fsanitize=undefined -fwrapv users likely want to suppress
signed-integer-overflow, unless signed-integer-overflow is explicitly
enabled. Implement this suppression.
chencha3 pushed a commit to chencha3/llvm-project that referenced this pull request Mar 23, 2024
…w if -fwrapv (llvm#85501)

Linux kernel uses -fwrapv to change signed integer overflows from
undefined behaviors to defined behaviors. However, the security folks
still want -fsanitize=signed-integer-overflow diagnostics. Their
intention can be expressed with -fwrapv
-fsanitize=signed-integer-overflow (llvm#80089). This mode by default
reports recoverable errors while still making signed integer overflows
defined (most UBSan checks are recoverable by default: you get errors in
stderr, but the program is not halted).

-fsanitize=undefined -fwrapv users likely want to suppress
signed-integer-overflow, unless signed-integer-overflow is explicitly
enabled. Implement this suppression.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category compiler-rt:sanitizer compiler-rt:ubsan Undefined behavior sanitizer compiler-rt
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants