Skip to content

Commit 81b4b89

Browse files
authored
[Sanitizer] Support -fwrapv with -fsanitize=signed-integer-overflow (#82432)
Clang has a `signed-integer-overflow` sanitizer to catch arithmetic overflow; however, most of its instrumentation [fails to apply](https://godbolt.org/z/ee41rE8o6) when `-fwrapv` is enabled; this is by design. The Linux kernel enables `-fno-strict-overflow` which implies `-fwrapv`. This means we are [currently unable to detect signed-integer wrap-around](KSPP/linux#26). All the while, the root cause of many security vulnerabilities in the Linux kernel is [arithmetic overflow](https://cwe.mitre.org/data/definitions/190.html). To work around this and enhance the functionality of `-fsanitize=signed-integer-overflow`, we instrument signed arithmetic even if the signed overflow behavior is defined. Co-authored-by: Justin Stitt <[email protected]>
1 parent 99c457d commit 81b4b89

File tree

4 files changed

+29
-10
lines changed

4 files changed

+29
-10
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,14 @@ Moved checkers
408408
Sanitizers
409409
----------
410410

411+
- ``-fsanitize=signed-integer-overflow`` now instruments signed arithmetic even
412+
when ``-fwrapv`` is enabled. Previously, only division checks were enabled.
413+
414+
Users with ``-fwrapv`` as well as a sanitizer group like
415+
``-fsanitize=undefined`` or ``-fsanitize=integer`` enabled may want to
416+
manually disable potentially noisy signed integer overflow checks with
417+
``-fno-sanitize=signed-integer-overflow``
418+
411419
Python Binding Changes
412420
----------------------
413421

clang/docs/UndefinedBehaviorSanitizer.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,11 @@ Available checks are:
190190
- ``-fsanitize=signed-integer-overflow``: Signed integer overflow, where the
191191
result of a signed integer computation cannot be represented in its type.
192192
This includes all the checks covered by ``-ftrapv``, as well as checks for
193-
signed division overflow (``INT_MIN/-1``), but not checks for
194-
lossy implicit conversions performed before the computation
195-
(see ``-fsanitize=implicit-conversion``). Both of these two issues are
196-
handled by ``-fsanitize=implicit-conversion`` group of checks.
193+
signed division overflow (``INT_MIN/-1``). Note that checks are still
194+
added even when ``-fwrapv`` is enabled. This sanitizer does not check for
195+
lossy implicit conversions performed before the computation (see
196+
``-fsanitize=implicit-conversion``). Both of these two issues are handled
197+
by ``-fsanitize=implicit-conversion`` group of checks.
197198
- ``-fsanitize=unreachable``: If control flow reaches an unreachable
198199
program point.
199200
- ``-fsanitize=unsigned-integer-overflow``: Unsigned integer overflow, where

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,9 @@ class ScalarExprEmitter
723723
if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
724724
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
725725
case LangOptions::SOB_Defined:
726-
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
726+
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
727+
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
728+
[[fallthrough]];
727729
case LangOptions::SOB_Undefined:
728730
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
729731
return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
@@ -2568,7 +2570,9 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior(
25682570
StringRef Name = IsInc ? "inc" : "dec";
25692571
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
25702572
case LangOptions::SOB_Defined:
2571-
return Builder.CreateAdd(InVal, Amount, Name);
2573+
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
2574+
return Builder.CreateAdd(InVal, Amount, Name);
2575+
[[fallthrough]];
25722576
case LangOptions::SOB_Undefined:
25732577
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
25742578
return Builder.CreateNSWAdd(InVal, Amount, Name);
@@ -3913,7 +3917,9 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
39133917
if (op.Ty->isSignedIntegerOrEnumerationType()) {
39143918
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
39153919
case LangOptions::SOB_Defined:
3916-
return Builder.CreateAdd(op.LHS, op.RHS, "add");
3920+
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
3921+
return Builder.CreateAdd(op.LHS, op.RHS, "add");
3922+
[[fallthrough]];
39173923
case LangOptions::SOB_Undefined:
39183924
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
39193925
return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
@@ -4067,7 +4073,9 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
40674073
if (op.Ty->isSignedIntegerOrEnumerationType()) {
40684074
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
40694075
case LangOptions::SOB_Defined:
4070-
return Builder.CreateSub(op.LHS, op.RHS, "sub");
4076+
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
4077+
return Builder.CreateSub(op.LHS, op.RHS, "sub");
4078+
[[fallthrough]];
40714079
case LangOptions::SOB_Undefined:
40724080
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
40734081
return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");

clang/test/CodeGen/integer-overflow.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s --check-prefix=DEFAULT
22
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fwrapv | FileCheck %s --check-prefix=WRAPV
33
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -ftrapv | FileCheck %s --check-prefix=TRAPV
4-
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fsanitize=signed-integer-overflow | FileCheck %s --check-prefix=CATCH_UB
4+
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fsanitize=signed-integer-overflow | FileCheck %s --check-prefixes=CATCH_UB,CATCH_UB_POINTER
5+
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fsanitize=signed-integer-overflow -fwrapv | FileCheck %s --check-prefixes=CATCH_UB,NOCATCH_UB_POINTER
56
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -ftrapv -ftrapv-handler foo | FileCheck %s --check-prefix=TRAPV_HANDLER
67

78

@@ -62,7 +63,8 @@ void test1(void) {
6263
// DEFAULT: getelementptr inbounds i32, ptr
6364
// WRAPV: getelementptr i32, ptr
6465
// TRAPV: getelementptr inbounds i32, ptr
65-
// CATCH_UB: getelementptr inbounds i32, ptr
66+
// CATCH_UB_POINTER: getelementptr inbounds i32, ptr
67+
// NOCATCH_UB_POINTER: getelementptr i32, ptr
6668

6769
// PR9350: char pre-increment never overflows.
6870
extern volatile signed char PR9350_char_inc;

0 commit comments

Comments
 (0)