[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
https://github.com/JustinStitt created https://github.com/llvm/llvm-project/pull/86618 ## Intro This attribute would allow for more granular control over what expressions can emit integer overflow warnings or integer overflow sanitizer errors. Here are some examples: _copy-pasted from my [RFC.](https://discourse.llvm.org/t/rfc-add-wraps-attribute-for-granular-integer-overflow-handling/77670)_ When compiling with `-fsanitize=signed-integer-overflow,unsigned-integer-overflow`: ```c typedef int __attribute__((wraps)) wrapping_int; wrapping_int A = INT_MAX; ++A; /* This will not trigger a runtime sanitizer error */ ``` ```c unsigned long addr __attribute__((wraps)); /* wraps can be added to variables */ unsigned long size; /* both operands don't need wraps, just one */ ... if (addr + size < addr) { // handle overflow gracefully, because the overflow sanitizer won't trip } ... ``` ```c typedef int __attribute__((wraps)) wrapping_int; int a = (wrapping_int) INT_MAX + 1; // no sanitizer trip (or -Winteger-overflow) ``` The next few examples will show some cases where sanitizers will still trip (by design): ```c wrapping_int A = INT_MAX; int B = 1; A = INT_MAX + 1; // overflow sanitizer trips! (INT_MAX + 1) is computed and trips the sanitizer before assignment to A B = (INT_MAX+B) * A; // overflow sanitizer trips! B = INT_MAX + B * A; // overflow sanitizer does NOT trip! // This is because B * A is computed first, the result type carries the wraps attribute // with it from A, then that result is used in summation with INT_MAX. ``` ## Reasoning The root cause of many security vulnerabilities in the Linux kernel is [arithmetic overflow](https://cwe.mitre.org/data/definitions/190.html). The currently available choices to control arithmetic overflow behavior are very limited. The instrumentation is "all or nothing" which lacks the granularity required for many cases. Enabling or disabling a sanitizer like ``-fsanitize=unsigned-integer-overflow`` completely opts you in or out of instrumentation for __all__ unsigned arithmetic. For functions where intentional wrap-around is performed you could use ``__attribute__((no_sanitize("unsigned-integer-overflow")))`` to completely disable sanitizer instrumentation. This, however, is not ideal if your function is large and multi-purposed -- perhaps even containing loads of arithmetic that you don't want to disable instrumentation for. Getting more granular, we have compiler built-ins like ``__builtin_add_overflow()`` or similar. However, in some codebases, refactoring existing arithmetic to utilize these overflow builtins may only serve to complicate code. For example, the Linux Kernel has, like lots of other projects, some agreed upon idioms which are understood by its developers and changing these patterns is [frowned upon](https://lore.kernel.org/all/CAHk-=whs7fsbboo1gxe+83two2jegnsukmhacfwymw9auqb...@mail.gmail.com): "if there's some unsigned wrap-around checker that doesn't understand this traditional way of doing overflow checking, that piece of crap needs fixing." - Linus This was in response to a patch that was trying to change the commonly accepted idiom: `base + offset < base` to utilize a builtin (via a macro) to silence sanitizer errors. Recently, there's been some effort by Kees, myself and others to reintroduce the signed and unsigned integer overflow sanitizers in the Linux Kernel. Upon turning these sanitizers back on (or for the case of signed-integer-overflow, [making it work at all](https://github.com/llvm/llvm-project/pull/82432)) we encountered plently of existing instances of integer overflow in the Kernel. However, there's some pushback when trying to alter the "traditional" way of doing things. With this new wrapping attribute we can specifically craft types that disable overflow instrumentation, without modifying traditional and widely understood code patterns -- resulting in easier to read code. ### To summarize the behavior: Using ``__attribute__((wraps))`` on a typedef or variable declaration makes it a "wrapping" type or variable thereby disabling overflow instrumentation for either 1) arithmetic performed directly on wrapping variables or types or 2) arithmetic performed on the result of calculations containing a wrapping variable or type. Instrumentation is not disabled for calculations containing subexpressions wherein no wrapping variables are present. ## Other Notes * ``[[wraps]]`` and ``[[clang::wraps]]`` are supported for C++11 * The wraps attribute cannot be applied to functions * The wraps attribute _can_ be applied to member variables * Constant expressions containing a wrapping type or variable should not result in `-Winteger-overflow` warnings either. ### CCs @kees @nickdesaulniers @bwendling @erichkeane @haoNoQ @apple-fcloutier @FlashSheridan >From 0fa8f07c722f9d7f80a90824f961ae6e9c5bdef7 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 5 Mar 2
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/86618 >From 0fa8f07c722f9d7f80a90824f961ae6e9c5bdef7 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 5 Mar 2024 03:14:49 + Subject: [PATCH 1/2] implement wraps attribute Signed-off-by: Justin Stitt --- clang/docs/ReleaseNotes.rst | 7 ++ clang/include/clang/AST/Expr.h| 3 + clang/include/clang/Basic/Attr.td | 6 ++ clang/include/clang/Basic/AttrDocs.td | 66 +++ .../clang/Basic/DiagnosticSemaKinds.td| 3 + clang/include/clang/Sema/Sema.h | 4 ++ clang/lib/AST/Expr.cpp| 19 ++ clang/lib/AST/ExprConstant.cpp| 6 +- clang/lib/AST/TypePrinter.cpp | 3 + clang/lib/CodeGen/CGExprScalar.cpp| 40 +-- clang/lib/Sema/SemaDeclAttr.cpp | 12 +++- clang/lib/Sema/SemaType.cpp | 15 + clang/test/CodeGen/integer-overflow.c | 56 clang/test/CodeGen/unsigned-overflow.c| 63 +++--- clang/test/Sema/attr-wraps.c | 9 +++ 15 files changed, 296 insertions(+), 16 deletions(-) create mode 100644 clang/test/Sema/attr-wraps.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 7fbe2fec6ca065..20bb9815830592 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -248,6 +248,13 @@ Attribute Changes in Clang added a new extension query ``__has_extension(swiftcc)`` corresponding to the ``__attribute__((swiftcc))`` attribute. +- Introduced ``__attribute((wraps))`` or ``[[wraps]]`` which can be added to + type or variable declarations. Using an attributed type or variable in an + arithmetic expression will define the overflow behavior for that expression + as having two's complement wrap-around. These expressions cannot trigger + integer overflow warnings or sanitizer warnings. They also cannot be + optimized away by some eager UB optimizations. + Improvements to Clang's diagnostics --- - Clang now applies syntax highlighting to the code snippets it diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 6e153ebe024b42..934146e8a182bc 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -4084,6 +4084,9 @@ class BinaryOperator : public Expr { static unsigned sizeOfTrailingObjects(bool HasFPFeatures) { return HasFPFeatures * sizeof(FPOptionsOverride); } + + /// Do one of the subexpressions have the wraps attribute? + bool oneOfWraps(const ASTContext &Ctx) const; }; /// CompoundAssignOperator - For compound assignments (e.g. +=), we keep diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 3e03e55612645b..0ea7755791d82e 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4496,3 +4496,9 @@ def CodeAlign: StmtAttr { static constexpr int MaximumAlignment = 4096; }]; } + +def Wraps : DeclOrTypeAttr { + let Spellings = [Clang<"wraps">, CXX11<"", "wraps", 202403>]; + let Subjects = SubjectList<[Var, TypedefName, Field]>; + let Documentation = [WrapsDocs]; +} diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 9de14f608fd114..af662702edcffa 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8005,3 +8005,69 @@ requirement: } }]; } + +def WrapsDocs : Documentation { + let Category = DocCatField; + let Content = [{ +This attribute can be used with type or variable declarations to denote that +arithmetic containing these marked components have defined overflow behavior. +Specifically, the behavior is defined as being consistent with two's complement +wrap-around. For the purposes of sanitizers or warnings that concern themselves +with the definedness of integer arithmetic, they will cease to instrument or +warn about arithmetic that directly involves a "wrapping" component. + +For example, ``-fsanitize=signed-integer-overflow`` or ``-Winteger-overflow`` +will not warn about suspicious overflowing arithmetic -- assuming correct usage +of the wraps attribute. + +This example shows some basic usage of ``__attribute__((wraps))`` on a type +definition when building with ``-fsanitize=signed-integer-overflow`` + +.. code-block:: c + typedef int __attribute__((wraps)) wrapping_int; + + void foo() { +wrapping_int a = INT_MAX; +++a; // no sanitizer warning + } + + int main() { foo(); } + +In the following example, we use ``__attribute__((wraps))`` on a variable to +disable overflow instrumentation for arithmetic expressions it appears in. We +do so with a popular overflow-checking pattern which we might not want to trip +sanitizers (like ``-fsanitize=unsigned-integer-overflow``). + +.. code-block:: c + void foo(int offset)
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
JustinStitt wrote: cc: @MaskRay (since they also reviewed https://github.com/llvm/llvm-project/pull/82432) https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
JustinStitt wrote: > Adding attributes to types as type sugar (not part of the canonical type) is > generally problematic: non-canonical types are not reliably preserved > throughout the compiler, particularly in cases involving templates. I see, here's an example that currently breaks my attribute (without any special handling): ```c++ typedef int __attribute__((wraps)) wrapping_int; template void foo(T a) { ++a; // this will throw a sanitizer error because the generic method // created for this templated type is generic } int main(void) { wrapping_int A = INT_MAX; foo(A); } ``` > > Can we use a type qualifier here? FWICT, qualifiers are extremely sparse with only a handful existing at all. ``` Type.h +142: /// The collection of all-type qualifiers we support. /// Clang supports five independent qualifiers: /// * C99: const, volatile, and restrict /// * MS: __unaligned /// * Embedded C (TR18037): address spaces /// * Objective C: the GC attributes (none, weak, or strong) ``` Most if not all type qualifiers are strongly associated with how the storage memory of a type is handled. For the behavior needed out of `wraps`, I was thinking this kind of thing is typically done via an attribute. Something like [noderef](https://clang.llvm.org/docs/AttributeReference.html#noderef) is similar. You apply it to types which then adjusts Clang's handling of variables of that type. If it comes down to it, we can make this attribute only available for C under ``__attribute__(())`` or I can try to add support for templates to be made aware of specific type attributes. https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
JustinStitt wrote: ping! https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -0,0 +1,77 @@ +// 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 JustinStitt wrote: My patch does not touch SIO but in my testing I wanted it to be clear that SIO and SIW behave differently when `-fwrapv` is enabled. The tests more or less show this difference . https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
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 Date: Tue, 23 Jan 2024 23:28:42 + Subject: [PATCH 1/6] 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, 2> Checks; + SmallVector, 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(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(NotOve
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
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 Date: Tue, 23 Jan 2024 23:28:42 + Subject: [PATCH 1/8] add signed-integer-wrap sanitizer --- clang/include/clang/Basic/Sanitizers.def | 5 +- clang/lib/CodeGen/CGExprScalar.cpp | 62 +++- compiler-rt/lib/ubsan/ubsan_checks.inc | 2 + 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def index c2137e3f61f645..b987b26f93c39a 100644 --- a/clang/include/clang/Basic/Sanitizers.def +++ b/clang/include/clang/Basic/Sanitizers.def @@ -104,6 +104,7 @@ SANITIZER("shift-base", ShiftBase) SANITIZER("shift-exponent", ShiftExponent) SANITIZER_GROUP("shift", Shift, ShiftBase | ShiftExponent) SANITIZER("signed-integer-overflow", SignedIntegerOverflow) +SANITIZER("signed-integer-wrap", SignedIntegerWrap) SANITIZER("unreachable", Unreachable) SANITIZER("vla-bound", VLABound) SANITIZER("vptr", Vptr) @@ -144,7 +145,7 @@ SANITIZER_GROUP("undefined", Undefined, IntegerDivideByZero | NonnullAttribute | Null | ObjectSize | PointerOverflow | Return | ReturnsNonnullAttribute | Shift | SignedIntegerOverflow | Unreachable | VLABound | Function | -Vptr) +Vptr | SignedIntegerWrap) // -fsanitize=undefined-trap is an alias for -fsanitize=undefined. SANITIZER_GROUP("undefined-trap", UndefinedTrap, Undefined) @@ -179,7 +180,7 @@ SANITIZER_GROUP("implicit-conversion", ImplicitConversion, SANITIZER_GROUP("integer", Integer, ImplicitConversion | IntegerDivideByZero | Shift | SignedIntegerOverflow | UnsignedIntegerOverflow | -UnsignedShiftBase) +UnsignedShiftBase | SignedIntegerWrap) SANITIZER("local-bounds", LocalBounds) SANITIZER_GROUP("bounds", Bounds, ArrayBounds | LocalBounds) diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index aa805f291d1757..5c05a0d7524244 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -723,6 +723,11 @@ class ScalarExprEmitter if (Ops.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: +if (CGF.SanOpts.has(SanitizerKind::SignedIntegerWrap)) { + if (CanElideOverflowCheck(CGF.getContext(), Ops)) +return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul"); + return EmitOverflowCheckedBinOp(Ops); +} return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) @@ -2516,6 +2521,12 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior( StringRef Name = IsInc ? "inc" : "dec"; switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: +if (CGF.SanOpts.has(SanitizerKind::SignedIntegerWrap)) { + if (!E->canOverflow()) +return Builder.CreateNSWAdd(InVal, Amount, Name); + return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec( + E, InVal, IsInc, E->getFPFeaturesInEffect(CGF.getLangOpts(; +} return Builder.CreateAdd(InVal, Amount, Name); case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) @@ -3409,7 +3420,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) { - SmallVector, 2> Checks; + SmallVector, 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(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(NotOve
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -3554,12 +3572,20 @@ 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)) { JustinStitt wrote: Yes, fixed in [e964431](https://github.com/llvm/llvm-project/pull/80089/commits/e96443184c6059ab8c5b97badc9ecc7270d4d466) https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -0,0 +1,77 @@ +// 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 JustinStitt wrote: I moved the tests in [5497e8b](https://github.com/llvm/llvm-project/pull/80089/commits/5497e8bc6849bf64c1158ff16b4aa04fd9141920); as such, I am no longer adding tests related to SIO. https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -0,0 +1,77 @@ +// 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 JustinStitt wrote: Resolved in [5497e8b](https://github.com/llvm/llvm-project/pull/80089/commits/5497e8bc6849bf64c1158ff16b4aa04fd9141920) since the tests have been moved there is no issue with LABEL statements or prefixes. https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -0,0 +1,77 @@ +// Check that -fsanitize=signed-integer-wrap instruments with -fwrapv JustinStitt wrote: Gotcha, I did just that in [5497e8b](https://github.com/llvm/llvm-project/pull/80089/commits/5497e8bc6849bf64c1158ff16b4aa04fd9141920). Thanks Nick! https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
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 Date: Tue, 23 Jan 2024 23:28:42 + 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, 2> Checks; + SmallVector, 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(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(NotOve
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
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 Date: Tue, 23 Jan 2024 23:28:42 + Subject: [PATCH 01/10] 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, 2> Checks; + SmallVector, 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(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(NotO
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
JustinStitt wrote: > UBSan is documented clang/docs/UndefinedBehaviorSanitizer.rst > https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html > > Please make sure to update the list [of available > checks](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#available-checks). > > Please also update the release notes to mention this feature. > clang/docs/ReleaseNotes.rst > Gotcha, done in [e15b6e6](https://github.com/llvm/llvm-project/pull/80089/commits/e15b6e636c27d00a4ef8d0a0f8f648bdcf11d44b) and [b978be6](https://github.com/llvm/llvm-project/pull/80089/commits/b978be62ca2d841d82924b702e8ab2b865754227). https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt created https://github.com/llvm/llvm-project/pull/80089 **Reasoning** 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. The kernel enables `-fno-strict-overflow` which implies `-fwrapv`. This means we are [currently unable to detect signed-integer wrap-around](https://github.com/KSPP/linux/issues/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) 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](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf). * Perhaps this sanitizer does not belong in the **U**ndefined **B**ehavior 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 >From 68805d7871230033be43c1d87dfcd2aa2b668589 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 23 Jan 2024 23:28:42 + Subject: [PATCH 1/3] 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 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 (!CG
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/80089 >From 68805d7871230033be43c1d87dfcd2aa2b668589 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 23 Jan 2024 23:28:42 + Subject: [PATCH 1/4] 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 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, 2> Checks; + SmallVector, 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(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(NotOverflo
[compiler-rt] [clang] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/80089 >From 68805d7871230033be43c1d87dfcd2aa2b668589 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 23 Jan 2024 23:28:42 + Subject: [PATCH 1/5] 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 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, 2> Checks; + SmallVector, 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(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(NotOverflo
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -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 JustinStitt wrote: Makes sense. Fixed in [4848e38](https://github.com/llvm/llvm-project/pull/80089/commits/4848e38223c4191c2e7d45839c2ec34341597c6c). https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -0,0 +1,77 @@ +// Check that -fsanitize=signed-integer-wrap instruments with -fwrapv JustinStitt wrote: I must be doing something wrong because it suggest I remove all my `Check: ...`'s and replcae them with `Check: {{.*}}` https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -0,0 +1,77 @@ +// 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 JustinStitt wrote: > `CHECK` is the implicit default prefix if otherwise unspecified. Being > explicit here is not necessary and is discouraged (unlike the zen of python). Gotcha, should I rename Check to something else or just drop the --check-prefix entirely? Also, the non-instrumented vs instrumented version don't have too much in common. Should I still opt for this shared --check-prefixes approach? Here's what we're workin' with: clang -cc1 -fwrapv -triple x86_64-apple-darwin -emit-llvm -o - -fsanitize=signed-integer-wrap san.c ``` ; ModuleID = 'san.c' source_filename = "san.c" target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-darwin" @b = external global i32, align 4 @c = external global i32, align 4 @.src = private unnamed_addr constant [6 x i8] c"san.c\00", align 1 @0 = private unnamed_addr constant { i16, i16, [6 x i8] } { i16 0, i16 11, [6 x i8] c"'int'\00" } @1 = private unnamed_addr global { { ptr, i32, i32 }, ptr } { { ptr, i32, i32 } { ptr @.src, i32 4, i32 9 }, ptr @0 } @a = external global i32, align 4 ; Function Attrs: noinline nounwind optnone define void @test_add_overflow() #0 { entry: %0 = load volatile i32, ptr @b, align 4 %1 = load volatile i32, ptr @c, align 4 %2 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %0, i32 %1), !nosanitize !2 %3 = extractvalue { i32, i1 } %2, 0, !nosanitize !2 %4 = extractvalue { i32, i1 } %2, 1, !nosanitize !2 %5 = xor i1 %4, true, !nosanitize !2 br i1 %5, label %cont, label %handler.add_overflow, !prof !3, !nosanitize !2 handler.add_overflow: ; preds = %entry %6 = zext i32 %0 to i64, !nosanitize !2 %7 = zext i32 %1 to i64, !nosanitize !2 call void @__ubsan_handle_add_overflow_abort(ptr @1, i64 %6, i64 %7) #3, !nosanitize !2 unreachable, !nosanitize !2 cont: ; preds = %entry store volatile i32 %3, ptr @a, align 4 ret void } ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) #1 ; Function Attrs: noreturn nounwind uwtable declare void @__ubsan_handle_add_overflow_abort(ptr, i64, i64) #2 attributes #0 = { noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } attributes #2 = { noreturn nounwind uwtable } attributes #3 = { noreturn nounwind } !llvm.module.flags = !{!0} !llvm.ident = !{!1} !0 = !{i32 1, !"wchar_size", i32 4} !1 = !{!"clang version 19.0.0git (https://github.com/JustinStitt/llvm-project.git 3766054a825a7dd4ae69feb73c767029f86f912e)"} !2 = !{} !3 = !{!"branch_weights", i32 1048575, i32 1} ``` clang -cc1 -fwrapv -triple x86_64-apple-darwin -emit-llvm -o - -fsanitize=signed-integer-overflow san.c ``` ; ModuleID = 'san.c' source_filename = "san.c" target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-darwin" @b = external global i32, align 4 @c = external global i32, align 4 @a = external global i32, align 4 ; Function Attrs: noinline nounwind optnone define void @test_add_overflow() #0 { entry: %0 = load volatile i32, ptr @b, align 4 %1 = load volatile i32, ptr @c, align 4 %add = add i32 %0, %1 store volatile i32 %add, ptr @a, align 4 ret void } attributes #0 = { noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } !llvm.module.flags = !{!0} !llvm.ident = !{!1} !0 = !{i32 1, !"wchar_size", i32 4} !1 = !{!"clang version 19.0.0git (https://github.com/JustinStitt/llvm-project.git 3766054a825a7dd4ae69feb73c767029f86f912e)"} ``` diff ```diff 8,10d7 < @.src = private unnamed_addr constant [6 x i8] c"san.c\00", align 1 < @0 = private unnamed_addr constant { i16, i16, [6 x i8] } { i16 0, i16 11, [6 x i8] c"'int'\00" } < @1 = private unnamed_addr global { { ptr, i32, i32 }, ptr } { { ptr, i32, i32 } { ptr @.src, i32 4, i32 9 }, ptr @0 } 18,31c15,16 < %2 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %0, i32 %1), !nosanitize !2 < %3 = extractvalue { i32, i1 } %2, 0, !nosanitize !2 < %4 = extractvalue { i32, i1 } %2, 1, !nosanitize !2 < %5 = xor i1 %4, true, !nosanitize !2 < br i1 %5, label %cont, label %handler.add_overflow, !prof !3, !nosanitize !2 < < handler.add_overflow: ; preds = %entry < %6 = zext i32 %0 to i64, !
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
JustinStitt wrote: Hey, does anyone know why the CI bot (buildkite) fails my builds for a trailing whitespace in a file I did not touch? https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[compiler-rt] [clang] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/80089 >From 68805d7871230033be43c1d87dfcd2aa2b668589 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 23 Jan 2024 23:28:42 + Subject: [PATCH 1/6] 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 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, 2> Checks; + SmallVector, 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(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(NotOverflo
[compiler-rt] [clang] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -0,0 +1,77 @@ +// 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 JustinStitt wrote: Gotcha. Fixed in [f790b65](https://github.com/llvm/llvm-project/pull/80089/commits/f790b6522166cc59d900400f9e7beee5d8a19750). Thanks Nick! https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -0,0 +1,77 @@ +// 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 JustinStitt wrote: I believe @tschuett was saying that to be confident we are instrumenting the arithmetic (and the correct operands therein) we should check the overflow bit usage in the branch instruction. The only way I could think of doing this was capturing the call to the overflow intrinsic which returns the value and the overflow bit. Is there a way to minimize my CHECKs? https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -0,0 +1,77 @@ +// Check that -fsanitize=signed-integer-wrap instruments with -fwrapv JustinStitt wrote: I believe @tschuett was saying that to be confident we are instrumenting the arithmetic (and the correct operands therein) we should check the overflow bit usage in the branch instruction. The only way I could think of doing this was capturing the call to the overflow intrinsic which returns the value and the overflow bit. Is there a way to minimize my CHECKs? https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt deleted https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -0,0 +1,77 @@ +// 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 JustinStitt wrote: I was thinking to be certain that no instrumentation exists we just need to check that no call to the handler exists. The idea being that it's easier to disprove something than to prove it. https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CodeGen] Respect pointer-overflow sanitizer for void pointers (PR #67772)
https://github.com/JustinStitt approved this pull request. LGTM! FWIW, here's a test file that does not trip the sanitizer before this PR and _does_ trip after the PR: ```c #include int main(int argc, char **argv) { void *p = NULL; printf("p: %p\n", p); p = p - argc; printf("p: %p\n", p); return 0; } ``` https://github.com/llvm/llvm-project/pull/67772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
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 Date: Tue, 23 Jan 2024 23:28:42 + Subject: [PATCH 01/11] 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, 2> Checks; + SmallVector, 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(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(NotO
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
JustinStitt wrote: > 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) https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
JustinStitt wrote: My original idea was to get the SIO sanitizer working with `-fwrapv`, the issue [here](https://github.com/KSPP/linux/issues/26) even suggests it as a viable option. However, after seeing literal checks like: ```cpp case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) ``` ... I think the best option is to instrument 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). https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
JustinStitt wrote: > 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](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf)) 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. https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -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. JustinStitt wrote: I was going off the spec, but I think I may have misinterpreted it: ` 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](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf) 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). I can add a check for the signed overflow behavior for the division steps. https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -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. JustinStitt wrote: > 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" wrap sanitize 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. https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
@@ -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 JustinStitt wrote: 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? https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Sanitizer: Support -fwrapv with -fsanitize=signed-integer-overflow (PR #82432)
https://github.com/JustinStitt created https://github.com/llvm/llvm-project/pull/82432 **Reasoning** 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](https://github.com/KSPP/linux/issues/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`, let's instrument signed arithmetic even if the signed overflow behavior is defined. Initially, I created a [new sanitizer @ (pr/80089)](https://github.com/llvm/llvm-project/pull/80089) but simply changing the SIO sanitizer itself may be the better approach as per @MaskRay 's review from that PR. cc: @nickdesaulniers @kees @nathanchance @bwendling @MaskRay >From b02b09b9eb4f9a8ac60dd077d95c67b959db3b70 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 20 Feb 2024 22:21:02 + Subject: [PATCH] support fwrapv with signed int overflow sanitizer --- clang/docs/ReleaseNotes.rst | 3 +++ clang/docs/UndefinedBehaviorSanitizer.rst | 9 + clang/lib/CodeGen/CGExprScalar.cpp| 16 clang/test/CodeGen/integer-overflow.c | 12 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5bca2c965c866b..685b19cabeb82c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -399,6 +399,9 @@ Moved checkers Sanitizers -- +- ``-fsanitize=signed-integer-overflow`` now instruments signed arithmetic even + when ``-fwrapv`` is enabled. Previously, only division checks were enabled. + Python Binding Changes -- diff --git a/clang/docs/UndefinedBehaviorSanitizer.rst b/clang/docs/UndefinedBehaviorSanitizer.rst index b8ad3804f18903..8f58c92bd2a163 100644 --- a/clang/docs/UndefinedBehaviorSanitizer.rst +++ b/clang/docs/UndefinedBehaviorSanitizer.rst @@ -190,10 +190,11 @@ Available checks are: - ``-fsanitize=signed-integer-overflow``: Signed integer overflow, where the result of a signed integer computation cannot be represented in its type. This includes all the checks covered by ``-ftrapv``, as well as checks for - 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. + signed division overflow (``INT_MIN/-1``). Note that checks are still + added even when ``-fwrapv`` is enabled. This sanitizer does not check 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. - ``-fsanitize=unreachable``: If control flow reaches an unreachable program point. - ``-fsanitize=unsigned-integer-overflow``: Unsigned integer overflow, where diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 576734e460b9c1..7621d9bcdec991 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -723,7 +723,9 @@ class ScalarExprEmitter if (Ops.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: -return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); +if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) + return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); +[[fallthrough]]; case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul"); @@ -2568,7 +2570,9 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior( StringRef Name = IsInc ? "inc" : "dec"; switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: -return Builder.CreateAdd(InVal, Amount, Name); +if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) +return Builder.CreateAdd(InVal, Amount, Name); +[[fallthrough]]; case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWAdd(InVal, Amount, Name); @@ -3913,7 +3917,9 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) { if (op.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehav
[clang] Sanitizer: Support -fwrapv with -fsanitize=signed-integer-overflow (PR #82432)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/82432 >From b02b09b9eb4f9a8ac60dd077d95c67b959db3b70 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 20 Feb 2024 22:21:02 + Subject: [PATCH 1/2] support fwrapv with signed int overflow sanitizer --- clang/docs/ReleaseNotes.rst | 3 +++ clang/docs/UndefinedBehaviorSanitizer.rst | 9 + clang/lib/CodeGen/CGExprScalar.cpp| 16 clang/test/CodeGen/integer-overflow.c | 12 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5bca2c965c866b..685b19cabeb82c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -399,6 +399,9 @@ Moved checkers Sanitizers -- +- ``-fsanitize=signed-integer-overflow`` now instruments signed arithmetic even + when ``-fwrapv`` is enabled. Previously, only division checks were enabled. + Python Binding Changes -- diff --git a/clang/docs/UndefinedBehaviorSanitizer.rst b/clang/docs/UndefinedBehaviorSanitizer.rst index b8ad3804f18903..8f58c92bd2a163 100644 --- a/clang/docs/UndefinedBehaviorSanitizer.rst +++ b/clang/docs/UndefinedBehaviorSanitizer.rst @@ -190,10 +190,11 @@ Available checks are: - ``-fsanitize=signed-integer-overflow``: Signed integer overflow, where the result of a signed integer computation cannot be represented in its type. This includes all the checks covered by ``-ftrapv``, as well as checks for - 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. + signed division overflow (``INT_MIN/-1``). Note that checks are still + added even when ``-fwrapv`` is enabled. This sanitizer does not check 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. - ``-fsanitize=unreachable``: If control flow reaches an unreachable program point. - ``-fsanitize=unsigned-integer-overflow``: Unsigned integer overflow, where diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 576734e460b9c1..7621d9bcdec991 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -723,7 +723,9 @@ class ScalarExprEmitter if (Ops.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: -return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); +if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) + return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); +[[fallthrough]]; case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul"); @@ -2568,7 +2570,9 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior( StringRef Name = IsInc ? "inc" : "dec"; switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: -return Builder.CreateAdd(InVal, Amount, Name); +if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) +return Builder.CreateAdd(InVal, Amount, Name); +[[fallthrough]]; case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWAdd(InVal, Amount, Name); @@ -3913,7 +3917,9 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) { if (op.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: - return Builder.CreateAdd(op.LHS, op.RHS, "add"); + if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) +return Builder.CreateAdd(op.LHS, op.RHS, "add"); + [[fallthrough]]; case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWAdd(op.LHS, op.RHS, "add"); @@ -4067,7 +4073,9 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) { if (op.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: -return Builder.CreateSub(op.LHS, op.RHS, "sub"); +if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) + return Builder.CreateSub(op.LHS, op.RHS, "sub"); +[[fallthrough]]; case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWSub(op.LHS, op.RHS, "sub"); d
[clang] Sanitizer: Support -fwrapv with -fsanitize=signed-integer-overflow (PR #82432)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/82432 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Sanitizer: Support -fwrapv with -fsanitize=signed-integer-overflow (PR #82432)
JustinStitt wrote: > ⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️ > > You can test this locally with the following command: > View the diff from clang-format here. Fixed in [e5e92e6](https://github.com/llvm/llvm-project/pull/82432/commits/e5e92e6c07a9fbbac698a3b6bb4422f26ea06583) https://github.com/llvm/llvm-project/pull/82432 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Sanitizer: Support -fwrapv with -fsanitize=signed-integer-overflow (PR #82432)
@@ -723,7 +723,9 @@ class ScalarExprEmitter if (Ops.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: -return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); +if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) JustinStitt wrote: One creates `CreateMul` and other `CreateNSWMul`. I believe this is useful for optimizations later https://github.com/llvm/llvm-project/pull/82432 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Sanitizer: Support -fwrapv with -fsanitize=signed-integer-overflow (PR #82432)
@@ -399,6 +399,9 @@ Moved checkers Sanitizers -- +- ``-fsanitize=signed-integer-overflow`` now instruments signed arithmetic even + when ``-fwrapv`` is enabled. Previously, only division checks were enabled. JustinStitt wrote: Doesn't `-fno-sanitizer-signed-integer-overflow` already work? I did some [testing in godbolt](https://godbolt.org/z/oWdxvzs4P) and I am able to toggle this sanitizer on/off. https://github.com/llvm/llvm-project/pull/82432 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Sanitizer: Support -fwrapv with -fsanitize=signed-integer-overflow (PR #82432)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/82432 >From b02b09b9eb4f9a8ac60dd077d95c67b959db3b70 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 20 Feb 2024 22:21:02 + Subject: [PATCH 1/3] support fwrapv with signed int overflow sanitizer --- clang/docs/ReleaseNotes.rst | 3 +++ clang/docs/UndefinedBehaviorSanitizer.rst | 9 + clang/lib/CodeGen/CGExprScalar.cpp| 16 clang/test/CodeGen/integer-overflow.c | 12 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5bca2c965c866b..685b19cabeb82c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -399,6 +399,9 @@ Moved checkers Sanitizers -- +- ``-fsanitize=signed-integer-overflow`` now instruments signed arithmetic even + when ``-fwrapv`` is enabled. Previously, only division checks were enabled. + Python Binding Changes -- diff --git a/clang/docs/UndefinedBehaviorSanitizer.rst b/clang/docs/UndefinedBehaviorSanitizer.rst index b8ad3804f18903..8f58c92bd2a163 100644 --- a/clang/docs/UndefinedBehaviorSanitizer.rst +++ b/clang/docs/UndefinedBehaviorSanitizer.rst @@ -190,10 +190,11 @@ Available checks are: - ``-fsanitize=signed-integer-overflow``: Signed integer overflow, where the result of a signed integer computation cannot be represented in its type. This includes all the checks covered by ``-ftrapv``, as well as checks for - 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. + signed division overflow (``INT_MIN/-1``). Note that checks are still + added even when ``-fwrapv`` is enabled. This sanitizer does not check 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. - ``-fsanitize=unreachable``: If control flow reaches an unreachable program point. - ``-fsanitize=unsigned-integer-overflow``: Unsigned integer overflow, where diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 576734e460b9c1..7621d9bcdec991 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -723,7 +723,9 @@ class ScalarExprEmitter if (Ops.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: -return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); +if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) + return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); +[[fallthrough]]; case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul"); @@ -2568,7 +2570,9 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior( StringRef Name = IsInc ? "inc" : "dec"; switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: -return Builder.CreateAdd(InVal, Amount, Name); +if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) +return Builder.CreateAdd(InVal, Amount, Name); +[[fallthrough]]; case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWAdd(InVal, Amount, Name); @@ -3913,7 +3917,9 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) { if (op.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: - return Builder.CreateAdd(op.LHS, op.RHS, "add"); + if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) +return Builder.CreateAdd(op.LHS, op.RHS, "add"); + [[fallthrough]]; case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWAdd(op.LHS, op.RHS, "add"); @@ -4067,7 +4073,9 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) { if (op.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: -return Builder.CreateSub(op.LHS, op.RHS, "sub"); +if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) + return Builder.CreateSub(op.LHS, op.RHS, "sub"); +[[fallthrough]]; case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWSub(op.LHS, op.RHS, "sub"); d
[clang] Sanitizer: Support -fwrapv with -fsanitize=signed-integer-overflow (PR #82432)
@@ -399,6 +399,9 @@ Moved checkers Sanitizers -- +- ``-fsanitize=signed-integer-overflow`` now instruments signed arithmetic even + when ``-fwrapv`` is enabled. Previously, only division checks were enabled. JustinStitt wrote: Gotcha, resolved with [0182698](https://github.com/llvm/llvm-project/pull/82432/commits/018269881647673b530b8cb4611c7a380a5a1b5c). Let me know if this is detailed enough 😄 https://github.com/llvm/llvm-project/pull/82432 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Sanitizer: Support -fwrapv with -fsanitize=signed-integer-overflow (PR #82432)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/82432 >From b02b09b9eb4f9a8ac60dd077d95c67b959db3b70 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 20 Feb 2024 22:21:02 + Subject: [PATCH 1/4] support fwrapv with signed int overflow sanitizer --- clang/docs/ReleaseNotes.rst | 3 +++ clang/docs/UndefinedBehaviorSanitizer.rst | 9 + clang/lib/CodeGen/CGExprScalar.cpp| 16 clang/test/CodeGen/integer-overflow.c | 12 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5bca2c965c866b..685b19cabeb82c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -399,6 +399,9 @@ Moved checkers Sanitizers -- +- ``-fsanitize=signed-integer-overflow`` now instruments signed arithmetic even + when ``-fwrapv`` is enabled. Previously, only division checks were enabled. + Python Binding Changes -- diff --git a/clang/docs/UndefinedBehaviorSanitizer.rst b/clang/docs/UndefinedBehaviorSanitizer.rst index b8ad3804f18903..8f58c92bd2a163 100644 --- a/clang/docs/UndefinedBehaviorSanitizer.rst +++ b/clang/docs/UndefinedBehaviorSanitizer.rst @@ -190,10 +190,11 @@ Available checks are: - ``-fsanitize=signed-integer-overflow``: Signed integer overflow, where the result of a signed integer computation cannot be represented in its type. This includes all the checks covered by ``-ftrapv``, as well as checks for - 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. + signed division overflow (``INT_MIN/-1``). Note that checks are still + added even when ``-fwrapv`` is enabled. This sanitizer does not check 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. - ``-fsanitize=unreachable``: If control flow reaches an unreachable program point. - ``-fsanitize=unsigned-integer-overflow``: Unsigned integer overflow, where diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 576734e460b9c1..7621d9bcdec991 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -723,7 +723,9 @@ class ScalarExprEmitter if (Ops.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: -return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); +if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) + return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); +[[fallthrough]]; case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul"); @@ -2568,7 +2570,9 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior( StringRef Name = IsInc ? "inc" : "dec"; switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: -return Builder.CreateAdd(InVal, Amount, Name); +if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) +return Builder.CreateAdd(InVal, Amount, Name); +[[fallthrough]]; case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWAdd(InVal, Amount, Name); @@ -3913,7 +3917,9 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) { if (op.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: - return Builder.CreateAdd(op.LHS, op.RHS, "add"); + if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) +return Builder.CreateAdd(op.LHS, op.RHS, "add"); + [[fallthrough]]; case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWAdd(op.LHS, op.RHS, "add"); @@ -4067,7 +4073,9 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) { if (op.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: -return Builder.CreateSub(op.LHS, op.RHS, "sub"); +if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) + return Builder.CreateSub(op.LHS, op.RHS, "sub"); +[[fallthrough]]; case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWSub(op.LHS, op.RHS, "sub"); d
[clang] Sanitizer: Support -fwrapv with -fsanitize=signed-integer-overflow (PR #82432)
@@ -70,6 +77,7 @@ void test1(void) { // WRAPV: add i8 {{.*}}, 1 JustinStitt wrote: How's [1d9cb0a](https://github.com/llvm/llvm-project/pull/82432/commits/1d9cb0aca8985aa1636780b3ff9a863962cc2d57) look? https://github.com/llvm/llvm-project/pull/82432 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Sanitizer: Support -fwrapv with -fsanitize=signed-integer-overflow (PR #82432)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/82432 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/86618 >From 06250aa308d1662848726528bd31395fb2ad3ea0 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 5 Mar 2024 03:14:49 + Subject: [PATCH] implement wraps attribute Signed-off-by: Justin Stitt --- clang/docs/ReleaseNotes.rst | 10 +++ clang/include/clang/AST/Expr.h| 3 + clang/include/clang/AST/Type.h| 2 + clang/include/clang/Basic/Attr.td | 7 ++ clang/include/clang/Basic/AttrDocs.td | 68 +++ clang/include/clang/Basic/DiagnosticGroups.td | 6 ++ .../clang/Basic/DiagnosticSemaKinds.td| 7 ++ clang/lib/AST/Expr.cpp| 9 +++ clang/lib/AST/ExprConstant.cpp| 4 +- clang/lib/AST/Type.cpp| 4 ++ clang/lib/AST/TypePrinter.cpp | 3 + clang/lib/CodeGen/CGExprScalar.cpp| 46 + clang/lib/Sema/Sema.cpp | 3 + clang/lib/Sema/SemaChecking.cpp | 33 - clang/lib/Sema/SemaDeclAttr.cpp | 8 ++- clang/lib/Sema/SemaType.cpp | 15 clang/test/CodeGen/integer-overflow.c | 66 ++ clang/test/CodeGen/unsigned-overflow.c| 63 ++--- ...a-attribute-supported-attributes-list.test | 1 + clang/test/Sema/attr-wraps.c | 43 20 files changed, 375 insertions(+), 26 deletions(-) create mode 100644 clang/test/Sema/attr-wraps.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 1520f7a2916aae..e08240a8c1052e 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -230,6 +230,16 @@ Attribute Changes in Clang instantiation by accidentally allowing it in C++ in some circumstances. (#GH106864) +- Introduced ``__attribute((wraps))__`` which can be added to type or variable + declarations. Using an attributed type or variable in an arithmetic + expression will define the overflow behavior for that expression as having + two's complement wrap-around. These expressions cannot trigger integer + overflow warnings or sanitizer warnings. They also cannot be optimized away + by some eager UB optimizations. + + This attribute is only valid for C, as there are built-in language + alternatives for other languages. + Improvements to Clang's diagnostics --- diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 65104acda93825..8702bb60b1db13 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -4095,6 +4095,9 @@ class BinaryOperator : public Expr { return getFPFeaturesInEffect(LO).getAllowFEnvAccess(); } + /// Does one of the subexpressions have the wraps attribute? + bool hasWrappingOperand(const ASTContext &Ctx) const; + protected: BinaryOperator(const ASTContext &Ctx, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 853226118af407..1bc488de5b2f71 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1454,6 +1454,8 @@ class QualType { return getQualifiers().hasStrongOrWeakObjCLifetime(); } + bool hasWrapsAttr() const; + // true when Type is objc's weak and weak is enabled but ARC isn't. bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const; diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 8d2a362abc3c32..b6b4c8c2f35a7d 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4790,3 +4790,10 @@ def ClspvLibclcBuiltin: InheritableAttr { let Documentation = [ClspvLibclcBuiltinDoc]; let SimpleHandler = 1; } + +def Wraps : DeclOrTypeAttr { + let Spellings = [Clang<"wraps">]; + let Subjects = SubjectList<[Var, TypedefName, Field]>; + let Documentation = [WrapsDocs]; + let LangOpts = [COnly]; +} diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index ef077db298831f..60379e836ad788 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8415,3 +8415,71 @@ of ``nonallocating`` by the compiler. }]; } +def WrapsDocs : Documentation { + let Category = DocCatField; + let Content = [{ +This attribute can be used with type or variable declarations to denote that +arithmetic containing these marked components have defined overflow behavior. +Specifically, the behavior is defined as being consistent with two's complement +wrap-around. For the purposes of sanitizers or warnings that concern themselves +with the definedness of integer arithmetic, they will cease to instrument or +warn about arithmetic that directly involves a "wrapping" component. + +For example, ``-fsanitize=
[clang] [Clang] Implement type filtering for overflow/truncation sanitizers w/ SSCLs (PR #107332)
https://github.com/JustinStitt created https://github.com/llvm/llvm-project/pull/107332 [Related RFC](https://discourse.llvm.org/t/rfc-support-globpattern-add-operator-to-invert-matches/80683/5?u=justinstitt) ### Summary Implement type-based filtering via [Sanitizer Special Case Lists](https://clang.llvm.org/docs/SanitizerSpecialCaseList.html) for the arithmetic overflow and truncation sanitizers. Currently, using the `type:` prefix with these sanitizers does nothing. I've hooked up the SSCL parsing with Clang codegen so that we don't emit the overflow/truncation checks if the arithmetic contains an ignored type. ### Usefulness You can craft ignorelists that ignore specific types that are expected to overflow or wrap-around. For example, to ignore `my_type` from `unsigned-integer-overflow` instrumentation: ```bash $ cat ignorelist.txt [unsigned-integer-overflow] type:my_type $ cat foo.c typedef int my_type; void foo() { my_type a = 2147483647; ++a; } $ clang foo.c -fsanitize=signed-integer-overflow -fsanitize-ignorelist=ignorelist.txt ; ./a.out // --> no sanitizer error ``` If a type is functionally intended to overflow, like [refcount_t](https://kernsec.org/wiki/index.php/Kernel_Protections/refcount_t) and its associated APIs in the Linux kernel, then this type filtering would prove useful for reducing sanitizer noise. Currently, the Linux kernel dealt with this by [littering](https://elixir.bootlin.com/linux/v6.10.8/source/include/linux/refcount.h#L139 ) `__attribute__((no_sanitize("signed-integer-overflow")))` annotations on all the `refcount_t` APIs. I think this serves as an example of how a codebase could be made cleaner. We could make custom types that are filtered out in an ignorelist, allowing for types to be more expressive -- without the need for annotations. This accomplishes a similar goal to https://github.com/llvm/llvm-project/pull/86618. Yet another use case for this type filtering is whitelisting. We could ignore _all_ types, save a few. ```bash $ cat ignorelist.txt [implicit-signed-integer-truncation] type:* # ignore literally all types type:short=skip # except `short` $ cat bar.c // compile with -fsanitize=implicit-signed-integer-truncation void bar(int toobig) { char a = toobig; // not instrumented short b = toobig; // instrumented } ``` ### Other ways to accomplish the goal of sanitizer allowlisting/whitelisting * ignore list SSCL type support (this PR that you're reading) * [my sanitize-allowlist branch](https://github.com/llvm/llvm-project/compare/main...JustinStitt:llvm-project:sanitize-allowlist) - this just implements a sibling flag `-fsanitize-allowlist=`, removing some of the double negative logic present with `skip`/`ignore` when trying to whitelist something. * [Glob Negation](https://discourse.llvm.org/t/rfc-support-globpattern-add-operator-to-invert-matches/80683) - Implement a negation operator to the GlobPattern class so the ignorelist query can use them to simulate allowlisting Please let me know which of the three options we like best. They are not necessarily mutually exclusive. Here's [another related PR](https://github.com/llvm/llvm-project/pull/86618) which implements a `wraps` attribute. This can accomplish a similar goal to this PR but requires in-source changes to codebases and also covers a wider variety of integer definedness problems. ### CCs @kees @vitalybuka @bwendling >From 729329fc5769d913862281b8943471637ab30372 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 3 Sep 2024 18:28:53 -0700 Subject: [PATCH 1/3] hook up sscl categories with overflow/truncation sanitizers Signed-off-by: Justin Stitt --- clang/include/clang/AST/ASTContext.h | 3 + clang/lib/AST/ASTContext.cpp | 31 +++ clang/lib/CodeGen/CGExprScalar.cpp | 36 +++- clang/test/CodeGen/ubsan-type-ignorelist.cpp | 88 +--- 4 files changed, 144 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 89bb5768dbd40d..a9373c6102c010 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -807,6 +807,9 @@ class ASTContext : public RefCountedBase { const NoSanitizeList &getNoSanitizeList() const { return *NoSanitizeL; } + bool isTypeIgnoredBySanitizer(const SanitizerMask &Mask, +const QualType &Ty) const; + const XRayFunctionFilter &getXRayFilter() const { return *XRayFilter; } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index c61234aa4d1af1..bcda5fad585d67 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -817,6 +817,37 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( return CanonTTP; } +/// Check if a type can have its sanitizer instrumentation elided. +/// Determine this by its presence in a SCL alongside its specified categories. +/// For example
[clang] [Clang] Implement type filtering for overflow/truncation sanitizers w/ SSCLs (PR #107332)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/107332 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/100272 >From 154d3505ab13275086b3dffed67bcdcac52f79a3 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 23 Jul 2024 20:21:49 + Subject: [PATCH 1/8] implement idiom exclusions Add flag `-fno-sanitize-overflow-idioms` which disables integer overflow/truncation sanitizer instrumentation for common overflow-dependent code patterns. Signed-off-by: Justin Stitt --- clang/include/clang/AST/Expr.h| 5 + clang/include/clang/Basic/LangOptions.def | 2 + clang/include/clang/Driver/Options.td | 10 ++ clang/include/clang/Driver/SanitizerArgs.h| 1 + clang/lib/AST/Expr.cpp| 53 +++ clang/lib/CodeGen/CGExprScalar.cpp| 26 +++- clang/lib/Driver/SanitizerArgs.cpp| 7 + clang/lib/Driver/ToolChains/Clang.cpp | 7 + .../CodeGen/overflow-idiom-exclusion-fp.c | 77 ++ clang/test/CodeGen/overflow-idiom-exclusion.c | 141 ++ 10 files changed, 327 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGen/overflow-idiom-exclusion-fp.c create mode 100644 clang/test/CodeGen/overflow-idiom-exclusion.c diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 5b813bfc2faf9..c329ee061cf00 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3860,6 +3860,7 @@ class CStyleCastExpr final class BinaryOperator : public Expr { enum { LHS, RHS, END_EXPR }; Stmt *SubExprs[END_EXPR]; + bool isOverflowIdiom; public: typedef BinaryOperatorKind Opcode; @@ -4018,6 +4019,10 @@ class BinaryOperator : public Expr { return isShiftAssignOp(getOpcode()); } + bool ignoreOverflowSanitizers() const { +return isOverflowIdiom; + } + /// Return true if a binary operator using the specified opcode and operands /// would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized /// integer to a pointer. diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 0035092ce0d86..4619e2d8c4fb7 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -400,6 +400,8 @@ VALUE_LANGOPT(TrivialAutoVarInitMaxSize, 32, 0, "stop trivial automatic variable initialization if var size exceeds the specified size (in bytes). Must be greater than 0.") ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined, "signed integer overflow handling") +LANGOPT(IgnoreNegationOverflow, 1, 0, "ignore overflow caused by negation") +LANGOPT(SanitizeOverflowIdioms, 1, 1, "enable instrumentation for common overflow idioms") ENUM_LANGOPT(ThreadModel , ThreadModelKind, 2, ThreadModelKind::POSIX, "Thread Model") BENIGN_LANGOPT(ArrowDepth, 32, 256, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c8c56dbb51b28..f253f7535776b 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2558,6 +2558,16 @@ defm sanitize_stats : BoolOption<"f", "sanitize-stats", "Disable">, BothFlags<[], [ClangOption], " sanitizer statistics gathering.">>, Group; +defm sanitize_overflow_idioms : BoolFOption<"sanitize-overflow-idioms", + LangOpts<"SanitizeOverflowIdioms">, DefaultTrue, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption], " the instrumentation of common overflow idioms">>; +defm sanitize_negation_overflow : BoolFOption<"sanitize-negation-overflow", + LangOpts<"IgnoreNegationOverflow">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption], " integer overflow sanitizer instrumentation for negation">>; def fsanitize_thread_memory_access : Flag<["-"], "fsanitize-thread-memory-access">, Group, HelpText<"Enable memory access instrumentation in ThreadSanitizer (default)">; diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 47ef175302679..291739e1221d9 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -64,6 +64,7 @@ class SanitizerArgs { // True if cross-dso CFI support if provided by the system (i.e. Android). bool ImplicitCfiRuntime = false; bool NeedsMemProfRt = false; + bool SanitizeOverflowIdioms = true; bool HwasanUseAliases = false; llvm::AsanDetectStackUseAfterReturnMode AsanUseAfterReturn = llvm::AsanDetectStackUseAfterReturnMode::Invalid; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 9d5b8167d0ee6..c07560c92100d 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4759,6 +4759,54 @@ ParenListExpr *ParenListExpr::CreateEmpty(const ASTContext &Ctx, return new (Mem) ParenListExpr(EmptyShell(), NumExprs); } +namespace { +/// Certa
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
@@ -4248,6 +4248,22 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; } + if (auto *A = Args.getLastArg(OPT_fsanitize_overflow_pattern_exclusion_EQ)) { +for (int i = 0, n = A->getNumValues(); i != n; ++i) { + StringRef Value = A->getValue(i); + if (Value == "none") +Opts.OverflowPatternExclusionMask |= LangOptionsBase::None; JustinStitt wrote: resolved with 4b3efbb41ff86eeff15671b1d876e1ef6a58a536 https://github.com/llvm/llvm-project/pull/100272 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
@@ -0,0 +1,83 @@ +// Check for potential false positives from patterns that _almost_ match classic overflow-dependent or overflow-prone code patterns JustinStitt wrote: resolved in 4b3efbb41ff86eeff15671b1d876e1ef6a58a536 https://github.com/llvm/llvm-project/pull/100272 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
@@ -293,6 +293,40 @@ To silence reports from unsigned integer overflow, you can set ``-fsanitize-recover=unsigned-integer-overflow``, is particularly useful for providing fuzzing signal without blowing up logs. +Disabling instrumentation for common overflow patterns +-- + +There are certain overflow-dependent or overflow-prone code patterns which +produce a lot of noise for integer overflow/truncation sanitizers. To disable +instrumentation for these common patterns one should use +``-fsanitize-overflow-pattern-exclusion=``. + +Currently, this option supports three pervasive overflow-dependent code idioms: JustinStitt wrote: thanks. resolved in 4b3efbb41ff86eeff15671b1d876e1ef6a58a536 https://github.com/llvm/llvm-project/pull/100272 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
@@ -555,6 +570,11 @@ class LangOptions : public LangOptionsBase { /// The default stream kind used for HIP kernel launching. GPUDefaultStreamKind GPUDefaultStream; + /// Which overflow patterns should be excluded from sanitizer instrumentation + int OverflowPatternExclusionMask = 0; JustinStitt wrote: gotcha, resolved with 4b3efbb41ff86eeff15671b1d876e1ef6a58a536 https://github.com/llvm/llvm-project/pull/100272 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
@@ -293,6 +293,40 @@ To silence reports from unsigned integer overflow, you can set ``-fsanitize-recover=unsigned-integer-overflow``, is particularly useful for providing fuzzing signal without blowing up logs. +Disabling instrumentation for common overflow patterns +-- + +There are certain overflow-dependent or overflow-prone code patterns which +produce a lot of noise for integer overflow/truncation sanitizers. To disable +instrumentation for these common patterns one should use +``-fsanitize-overflow-pattern-exclusion=``. + +Currently, this option supports three pervasive overflow-dependent code idioms: + +.. code-block:: c++ + +/// -fsanitize-overflow-pattern-exclusion=negated-unsigned-const +unsigned long foo = -1UL; // No longer causes a negation overflow warning +unsigned long bar = -2UL; // and so on... + +.. code-block:: c++ + +/// -fsanitize-overflow-pattern-exclusion=post-decr-while +unsigned char count = 16; +while (count--) { /* ... */ } // No longer causes unsigned-integer-overflow sanitizer to trip + +.. code-block:: c++ + +/// -fsanitize-overflow-pattern-exclusion=add-overflow-test +if (base + offset < base) { /* ... */ } // The pattern of `a + b < a`, and other re-orderings, +// won't be instrumented (same for signed types) + +Negated unsigned constants, post-decrements in a while loop condition and JustinStitt wrote: right, that reads better. thanks! resolved with 4b3efbb41ff86eeff15671b1d876e1ef6a58a536 https://github.com/llvm/llvm-project/pull/100272 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
@@ -2877,6 +2888,17 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, } else if (type->isIntegerType()) { QualType promotedType; bool canPerformLossyDemotionCheck = false; + +// Is the pattern "while (i--)" and overflow exclusion? +bool disableSanitizer = JustinStitt wrote: You're right. I split up the logic into a new method in 4b3efbb41ff86eeff15671b1d876e1ef6a58a536 https://github.com/llvm/llvm-project/pull/100272 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
JustinStitt wrote: @bwendling I tried to address all your feedback points with 4b3efbb41ff86eeff15671b1d876e1ef6a58a536 Let me know how that looks 👍 https://github.com/llvm/llvm-project/pull/100272 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/100272 >From 154d3505ab13275086b3dffed67bcdcac52f79a3 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 23 Jul 2024 20:21:49 + Subject: [PATCH 1/9] implement idiom exclusions Add flag `-fno-sanitize-overflow-idioms` which disables integer overflow/truncation sanitizer instrumentation for common overflow-dependent code patterns. Signed-off-by: Justin Stitt --- clang/include/clang/AST/Expr.h| 5 + clang/include/clang/Basic/LangOptions.def | 2 + clang/include/clang/Driver/Options.td | 10 ++ clang/include/clang/Driver/SanitizerArgs.h| 1 + clang/lib/AST/Expr.cpp| 53 +++ clang/lib/CodeGen/CGExprScalar.cpp| 26 +++- clang/lib/Driver/SanitizerArgs.cpp| 7 + clang/lib/Driver/ToolChains/Clang.cpp | 7 + .../CodeGen/overflow-idiom-exclusion-fp.c | 77 ++ clang/test/CodeGen/overflow-idiom-exclusion.c | 141 ++ 10 files changed, 327 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGen/overflow-idiom-exclusion-fp.c create mode 100644 clang/test/CodeGen/overflow-idiom-exclusion.c diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 5b813bfc2faf90..c329ee061cf008 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3860,6 +3860,7 @@ class CStyleCastExpr final class BinaryOperator : public Expr { enum { LHS, RHS, END_EXPR }; Stmt *SubExprs[END_EXPR]; + bool isOverflowIdiom; public: typedef BinaryOperatorKind Opcode; @@ -4018,6 +4019,10 @@ class BinaryOperator : public Expr { return isShiftAssignOp(getOpcode()); } + bool ignoreOverflowSanitizers() const { +return isOverflowIdiom; + } + /// Return true if a binary operator using the specified opcode and operands /// would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized /// integer to a pointer. diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 0035092ce0d863..4619e2d8c4fb7f 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -400,6 +400,8 @@ VALUE_LANGOPT(TrivialAutoVarInitMaxSize, 32, 0, "stop trivial automatic variable initialization if var size exceeds the specified size (in bytes). Must be greater than 0.") ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined, "signed integer overflow handling") +LANGOPT(IgnoreNegationOverflow, 1, 0, "ignore overflow caused by negation") +LANGOPT(SanitizeOverflowIdioms, 1, 1, "enable instrumentation for common overflow idioms") ENUM_LANGOPT(ThreadModel , ThreadModelKind, 2, ThreadModelKind::POSIX, "Thread Model") BENIGN_LANGOPT(ArrowDepth, 32, 256, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c8c56dbb51b28a..f253f7535776b8 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2558,6 +2558,16 @@ defm sanitize_stats : BoolOption<"f", "sanitize-stats", "Disable">, BothFlags<[], [ClangOption], " sanitizer statistics gathering.">>, Group; +defm sanitize_overflow_idioms : BoolFOption<"sanitize-overflow-idioms", + LangOpts<"SanitizeOverflowIdioms">, DefaultTrue, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption], " the instrumentation of common overflow idioms">>; +defm sanitize_negation_overflow : BoolFOption<"sanitize-negation-overflow", + LangOpts<"IgnoreNegationOverflow">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption], " integer overflow sanitizer instrumentation for negation">>; def fsanitize_thread_memory_access : Flag<["-"], "fsanitize-thread-memory-access">, Group, HelpText<"Enable memory access instrumentation in ThreadSanitizer (default)">; diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 47ef175302679f..291739e1221d96 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -64,6 +64,7 @@ class SanitizerArgs { // True if cross-dso CFI support if provided by the system (i.e. Android). bool ImplicitCfiRuntime = false; bool NeedsMemProfRt = false; + bool SanitizeOverflowIdioms = true; bool HwasanUseAliases = false; llvm::AsanDetectStackUseAfterReturnMode AsanUseAfterReturn = llvm::AsanDetectStackUseAfterReturnMode::Invalid; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 9d5b8167d0ee62..c07560c92100d7 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4759,6 +4759,54 @@ ParenListExpr *ParenListExpr::CreateEmpty(const ASTContext &Ctx, return new (Mem) ParenListExpr(EmptyShell(), NumExprs); } +namespace {
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
@@ -4759,6 +4759,55 @@ ParenListExpr *ParenListExpr::CreateEmpty(const ASTContext &Ctx, return new (Mem) ParenListExpr(EmptyShell(), NumExprs); } +namespace { JustinStitt wrote: resolved by https://github.com/llvm/llvm-project/pull/100272/commits/2e3d4795633bb1a134be10b44e83a025a7b21d8e thanks https://github.com/llvm/llvm-project/pull/100272 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/100272 >From 154d3505ab13275086b3dffed67bcdcac52f79a3 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 23 Jul 2024 20:21:49 + Subject: [PATCH 01/10] implement idiom exclusions Add flag `-fno-sanitize-overflow-idioms` which disables integer overflow/truncation sanitizer instrumentation for common overflow-dependent code patterns. Signed-off-by: Justin Stitt --- clang/include/clang/AST/Expr.h| 5 + clang/include/clang/Basic/LangOptions.def | 2 + clang/include/clang/Driver/Options.td | 10 ++ clang/include/clang/Driver/SanitizerArgs.h| 1 + clang/lib/AST/Expr.cpp| 53 +++ clang/lib/CodeGen/CGExprScalar.cpp| 26 +++- clang/lib/Driver/SanitizerArgs.cpp| 7 + clang/lib/Driver/ToolChains/Clang.cpp | 7 + .../CodeGen/overflow-idiom-exclusion-fp.c | 77 ++ clang/test/CodeGen/overflow-idiom-exclusion.c | 141 ++ 10 files changed, 327 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGen/overflow-idiom-exclusion-fp.c create mode 100644 clang/test/CodeGen/overflow-idiom-exclusion.c diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 5b813bfc2faf90..c329ee061cf008 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3860,6 +3860,7 @@ class CStyleCastExpr final class BinaryOperator : public Expr { enum { LHS, RHS, END_EXPR }; Stmt *SubExprs[END_EXPR]; + bool isOverflowIdiom; public: typedef BinaryOperatorKind Opcode; @@ -4018,6 +4019,10 @@ class BinaryOperator : public Expr { return isShiftAssignOp(getOpcode()); } + bool ignoreOverflowSanitizers() const { +return isOverflowIdiom; + } + /// Return true if a binary operator using the specified opcode and operands /// would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized /// integer to a pointer. diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 0035092ce0d863..4619e2d8c4fb7f 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -400,6 +400,8 @@ VALUE_LANGOPT(TrivialAutoVarInitMaxSize, 32, 0, "stop trivial automatic variable initialization if var size exceeds the specified size (in bytes). Must be greater than 0.") ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined, "signed integer overflow handling") +LANGOPT(IgnoreNegationOverflow, 1, 0, "ignore overflow caused by negation") +LANGOPT(SanitizeOverflowIdioms, 1, 1, "enable instrumentation for common overflow idioms") ENUM_LANGOPT(ThreadModel , ThreadModelKind, 2, ThreadModelKind::POSIX, "Thread Model") BENIGN_LANGOPT(ArrowDepth, 32, 256, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c8c56dbb51b28a..f253f7535776b8 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2558,6 +2558,16 @@ defm sanitize_stats : BoolOption<"f", "sanitize-stats", "Disable">, BothFlags<[], [ClangOption], " sanitizer statistics gathering.">>, Group; +defm sanitize_overflow_idioms : BoolFOption<"sanitize-overflow-idioms", + LangOpts<"SanitizeOverflowIdioms">, DefaultTrue, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption], " the instrumentation of common overflow idioms">>; +defm sanitize_negation_overflow : BoolFOption<"sanitize-negation-overflow", + LangOpts<"IgnoreNegationOverflow">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption], " integer overflow sanitizer instrumentation for negation">>; def fsanitize_thread_memory_access : Flag<["-"], "fsanitize-thread-memory-access">, Group, HelpText<"Enable memory access instrumentation in ThreadSanitizer (default)">; diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 47ef175302679f..291739e1221d96 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -64,6 +64,7 @@ class SanitizerArgs { // True if cross-dso CFI support if provided by the system (i.e. Android). bool ImplicitCfiRuntime = false; bool NeedsMemProfRt = false; + bool SanitizeOverflowIdioms = true; bool HwasanUseAliases = false; llvm::AsanDetectStackUseAfterReturnMode AsanUseAfterReturn = llvm::AsanDetectStackUseAfterReturnMode::Invalid; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 9d5b8167d0ee62..c07560c92100d7 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4759,6 +4759,54 @@ ParenListExpr *ParenListExpr::CreateEmpty(const ASTContext &Ctx, return new (Mem) ParenListExpr(EmptyShell(), NumExprs); } +namespace
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
@@ -195,13 +196,23 @@ static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) { if (!Op.mayHaveIntegerOverflow()) return true; + const UnaryOperator *UO = dyn_cast(Op.E); + + if (UO && UO->getOpcode() == UO_Minus && UO->isIntegerConstantExpr(Ctx) && + Ctx.getLangOpts().isOverflowPatternExcluded( + LangOptions::OverflowPatternExclusionKind::NegUnsignedConst)) JustinStitt wrote: Nice catch, resolved in https://github.com/llvm/llvm-project/pull/100272/commits/cb0fcd1c3b1ded7258bb20cff4d187ca56f17149 https://github.com/llvm/llvm-project/pull/100272 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
@@ -3860,6 +3860,7 @@ class CStyleCastExpr final class BinaryOperator : public Expr { enum { LHS, RHS, END_EXPR }; Stmt *SubExprs[END_EXPR]; + bool ExcludedOverflowPattern = false; JustinStitt wrote: Ok, I think I found a spare bit in `BinaryOperatorBits` but I am not super familiar with how all these bit classes work. See: https://github.com/llvm/llvm-project/pull/100272/commits/cb0fcd1c3b1ded7258bb20cff4d187ca56f17149 Thanks https://github.com/llvm/llvm-project/pull/100272 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/100272 >From 154d3505ab13275086b3dffed67bcdcac52f79a3 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 23 Jul 2024 20:21:49 + Subject: [PATCH 01/11] implement idiom exclusions Add flag `-fno-sanitize-overflow-idioms` which disables integer overflow/truncation sanitizer instrumentation for common overflow-dependent code patterns. Signed-off-by: Justin Stitt --- clang/include/clang/AST/Expr.h| 5 + clang/include/clang/Basic/LangOptions.def | 2 + clang/include/clang/Driver/Options.td | 10 ++ clang/include/clang/Driver/SanitizerArgs.h| 1 + clang/lib/AST/Expr.cpp| 53 +++ clang/lib/CodeGen/CGExprScalar.cpp| 26 +++- clang/lib/Driver/SanitizerArgs.cpp| 7 + clang/lib/Driver/ToolChains/Clang.cpp | 7 + .../CodeGen/overflow-idiom-exclusion-fp.c | 77 ++ clang/test/CodeGen/overflow-idiom-exclusion.c | 141 ++ 10 files changed, 327 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGen/overflow-idiom-exclusion-fp.c create mode 100644 clang/test/CodeGen/overflow-idiom-exclusion.c diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 5b813bfc2faf90..c329ee061cf008 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3860,6 +3860,7 @@ class CStyleCastExpr final class BinaryOperator : public Expr { enum { LHS, RHS, END_EXPR }; Stmt *SubExprs[END_EXPR]; + bool isOverflowIdiom; public: typedef BinaryOperatorKind Opcode; @@ -4018,6 +4019,10 @@ class BinaryOperator : public Expr { return isShiftAssignOp(getOpcode()); } + bool ignoreOverflowSanitizers() const { +return isOverflowIdiom; + } + /// Return true if a binary operator using the specified opcode and operands /// would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized /// integer to a pointer. diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 0035092ce0d863..4619e2d8c4fb7f 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -400,6 +400,8 @@ VALUE_LANGOPT(TrivialAutoVarInitMaxSize, 32, 0, "stop trivial automatic variable initialization if var size exceeds the specified size (in bytes). Must be greater than 0.") ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined, "signed integer overflow handling") +LANGOPT(IgnoreNegationOverflow, 1, 0, "ignore overflow caused by negation") +LANGOPT(SanitizeOverflowIdioms, 1, 1, "enable instrumentation for common overflow idioms") ENUM_LANGOPT(ThreadModel , ThreadModelKind, 2, ThreadModelKind::POSIX, "Thread Model") BENIGN_LANGOPT(ArrowDepth, 32, 256, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c8c56dbb51b28a..f253f7535776b8 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2558,6 +2558,16 @@ defm sanitize_stats : BoolOption<"f", "sanitize-stats", "Disable">, BothFlags<[], [ClangOption], " sanitizer statistics gathering.">>, Group; +defm sanitize_overflow_idioms : BoolFOption<"sanitize-overflow-idioms", + LangOpts<"SanitizeOverflowIdioms">, DefaultTrue, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption], " the instrumentation of common overflow idioms">>; +defm sanitize_negation_overflow : BoolFOption<"sanitize-negation-overflow", + LangOpts<"IgnoreNegationOverflow">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption], " integer overflow sanitizer instrumentation for negation">>; def fsanitize_thread_memory_access : Flag<["-"], "fsanitize-thread-memory-access">, Group, HelpText<"Enable memory access instrumentation in ThreadSanitizer (default)">; diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 47ef175302679f..291739e1221d96 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -64,6 +64,7 @@ class SanitizerArgs { // True if cross-dso CFI support if provided by the system (i.e. Android). bool ImplicitCfiRuntime = false; bool NeedsMemProfRt = false; + bool SanitizeOverflowIdioms = true; bool HwasanUseAliases = false; llvm::AsanDetectStackUseAfterReturnMode AsanUseAfterReturn = llvm::AsanDetectStackUseAfterReturnMode::Invalid; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 9d5b8167d0ee62..c07560c92100d7 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4759,6 +4759,54 @@ ParenListExpr *ParenListExpr::CreateEmpty(const ASTContext &Ctx, return new (Mem) ParenListExpr(EmptyShell(), NumExprs); } +namespace
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
@@ -649,6 +649,8 @@ class alignas(void *) Stmt { /// It is 0 otherwise. LLVM_PREFERRED_TYPE(bool) unsigned HasFPFeatures : 1; +LLVM_PREFERRED_TYPE(bool) JustinStitt wrote: Good idea, see https://github.com/llvm/llvm-project/pull/100272/commits/e8afeed6dfc5d427b83d52d69c8f92b27fd1220e thanks https://github.com/llvm/llvm-project/pull/100272 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
JustinStitt wrote: > I think serialization is missing for the new bit on BinaryOperator. How do I add this? > I'm not sure why we're storing it in the first place, though; it's queried in > exactly one place, so there isn't really any benefit to precomputing it. It's queried when we check if we can elide the overflow sanitizer check, at this point we're dealing with the BO responsible for the addition (or subtraction) and not with the BO responsible for comparison. To properly check for the entire pattern I am trying to exclude I am pretty sure I need that comparison BO; so I can either precompute comparison BOs and store a bit on its child BO or I navigate up the parent map from the child during the overflow ellision check. Which is the better approach? https://github.com/llvm/llvm-project/pull/100272 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
JustinStitt wrote: A good example of a Linux kernel contributor running into an overflow that should really have its type marked as wrapping : https://lore.kernel.org/all/zrzk8hiladaj+...@gmail.com/ They could use this feature to mark the suspected field `percpu_ref->percpu_ref_data->count` as wrapping: ```c struct percpu_ref_data { atomic_long_t count __attribute__((wraps)); ... }; // or mark the type `atomic_long_t` as wrapping typedef atomic_t __attribute__((wraps)) atomic_long_t; ``` Reviewers, can I get a sense of where we are at with this feature? It lets developers better express the behavior of arithmetic in their code. https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/100272 >From 154d3505ab13275086b3dffed67bcdcac52f79a3 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 23 Jul 2024 20:21:49 + Subject: [PATCH 01/12] implement idiom exclusions Add flag `-fno-sanitize-overflow-idioms` which disables integer overflow/truncation sanitizer instrumentation for common overflow-dependent code patterns. Signed-off-by: Justin Stitt --- clang/include/clang/AST/Expr.h| 5 + clang/include/clang/Basic/LangOptions.def | 2 + clang/include/clang/Driver/Options.td | 10 ++ clang/include/clang/Driver/SanitizerArgs.h| 1 + clang/lib/AST/Expr.cpp| 53 +++ clang/lib/CodeGen/CGExprScalar.cpp| 26 +++- clang/lib/Driver/SanitizerArgs.cpp| 7 + clang/lib/Driver/ToolChains/Clang.cpp | 7 + .../CodeGen/overflow-idiom-exclusion-fp.c | 77 ++ clang/test/CodeGen/overflow-idiom-exclusion.c | 141 ++ 10 files changed, 327 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGen/overflow-idiom-exclusion-fp.c create mode 100644 clang/test/CodeGen/overflow-idiom-exclusion.c diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 5b813bfc2faf90..c329ee061cf008 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3860,6 +3860,7 @@ class CStyleCastExpr final class BinaryOperator : public Expr { enum { LHS, RHS, END_EXPR }; Stmt *SubExprs[END_EXPR]; + bool isOverflowIdiom; public: typedef BinaryOperatorKind Opcode; @@ -4018,6 +4019,10 @@ class BinaryOperator : public Expr { return isShiftAssignOp(getOpcode()); } + bool ignoreOverflowSanitizers() const { +return isOverflowIdiom; + } + /// Return true if a binary operator using the specified opcode and operands /// would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized /// integer to a pointer. diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 0035092ce0d863..4619e2d8c4fb7f 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -400,6 +400,8 @@ VALUE_LANGOPT(TrivialAutoVarInitMaxSize, 32, 0, "stop trivial automatic variable initialization if var size exceeds the specified size (in bytes). Must be greater than 0.") ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined, "signed integer overflow handling") +LANGOPT(IgnoreNegationOverflow, 1, 0, "ignore overflow caused by negation") +LANGOPT(SanitizeOverflowIdioms, 1, 1, "enable instrumentation for common overflow idioms") ENUM_LANGOPT(ThreadModel , ThreadModelKind, 2, ThreadModelKind::POSIX, "Thread Model") BENIGN_LANGOPT(ArrowDepth, 32, 256, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c8c56dbb51b28a..f253f7535776b8 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2558,6 +2558,16 @@ defm sanitize_stats : BoolOption<"f", "sanitize-stats", "Disable">, BothFlags<[], [ClangOption], " sanitizer statistics gathering.">>, Group; +defm sanitize_overflow_idioms : BoolFOption<"sanitize-overflow-idioms", + LangOpts<"SanitizeOverflowIdioms">, DefaultTrue, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption], " the instrumentation of common overflow idioms">>; +defm sanitize_negation_overflow : BoolFOption<"sanitize-negation-overflow", + LangOpts<"IgnoreNegationOverflow">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption], " integer overflow sanitizer instrumentation for negation">>; def fsanitize_thread_memory_access : Flag<["-"], "fsanitize-thread-memory-access">, Group, HelpText<"Enable memory access instrumentation in ThreadSanitizer (default)">; diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 47ef175302679f..291739e1221d96 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -64,6 +64,7 @@ class SanitizerArgs { // True if cross-dso CFI support if provided by the system (i.e. Android). bool ImplicitCfiRuntime = false; bool NeedsMemProfRt = false; + bool SanitizeOverflowIdioms = true; bool HwasanUseAliases = false; llvm::AsanDetectStackUseAfterReturnMode AsanUseAfterReturn = llvm::AsanDetectStackUseAfterReturnMode::Invalid; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 9d5b8167d0ee62..c07560c92100d7 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4759,6 +4759,54 @@ ParenListExpr *ParenListExpr::CreateEmpty(const ASTContext &Ctx, return new (Mem) ParenListExpr(EmptyShell(), NumExprs); } +namespace
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/100272 >From 154d3505ab13275086b3dffed67bcdcac52f79a3 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 23 Jul 2024 20:21:49 + Subject: [PATCH 01/13] implement idiom exclusions Add flag `-fno-sanitize-overflow-idioms` which disables integer overflow/truncation sanitizer instrumentation for common overflow-dependent code patterns. Signed-off-by: Justin Stitt --- clang/include/clang/AST/Expr.h| 5 + clang/include/clang/Basic/LangOptions.def | 2 + clang/include/clang/Driver/Options.td | 10 ++ clang/include/clang/Driver/SanitizerArgs.h| 1 + clang/lib/AST/Expr.cpp| 53 +++ clang/lib/CodeGen/CGExprScalar.cpp| 26 +++- clang/lib/Driver/SanitizerArgs.cpp| 7 + clang/lib/Driver/ToolChains/Clang.cpp | 7 + .../CodeGen/overflow-idiom-exclusion-fp.c | 77 ++ clang/test/CodeGen/overflow-idiom-exclusion.c | 141 ++ 10 files changed, 327 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGen/overflow-idiom-exclusion-fp.c create mode 100644 clang/test/CodeGen/overflow-idiom-exclusion.c diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 5b813bfc2faf90..c329ee061cf008 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3860,6 +3860,7 @@ class CStyleCastExpr final class BinaryOperator : public Expr { enum { LHS, RHS, END_EXPR }; Stmt *SubExprs[END_EXPR]; + bool isOverflowIdiom; public: typedef BinaryOperatorKind Opcode; @@ -4018,6 +4019,10 @@ class BinaryOperator : public Expr { return isShiftAssignOp(getOpcode()); } + bool ignoreOverflowSanitizers() const { +return isOverflowIdiom; + } + /// Return true if a binary operator using the specified opcode and operands /// would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized /// integer to a pointer. diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 0035092ce0d863..4619e2d8c4fb7f 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -400,6 +400,8 @@ VALUE_LANGOPT(TrivialAutoVarInitMaxSize, 32, 0, "stop trivial automatic variable initialization if var size exceeds the specified size (in bytes). Must be greater than 0.") ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined, "signed integer overflow handling") +LANGOPT(IgnoreNegationOverflow, 1, 0, "ignore overflow caused by negation") +LANGOPT(SanitizeOverflowIdioms, 1, 1, "enable instrumentation for common overflow idioms") ENUM_LANGOPT(ThreadModel , ThreadModelKind, 2, ThreadModelKind::POSIX, "Thread Model") BENIGN_LANGOPT(ArrowDepth, 32, 256, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c8c56dbb51b28a..f253f7535776b8 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2558,6 +2558,16 @@ defm sanitize_stats : BoolOption<"f", "sanitize-stats", "Disable">, BothFlags<[], [ClangOption], " sanitizer statistics gathering.">>, Group; +defm sanitize_overflow_idioms : BoolFOption<"sanitize-overflow-idioms", + LangOpts<"SanitizeOverflowIdioms">, DefaultTrue, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption], " the instrumentation of common overflow idioms">>; +defm sanitize_negation_overflow : BoolFOption<"sanitize-negation-overflow", + LangOpts<"IgnoreNegationOverflow">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption], " integer overflow sanitizer instrumentation for negation">>; def fsanitize_thread_memory_access : Flag<["-"], "fsanitize-thread-memory-access">, Group, HelpText<"Enable memory access instrumentation in ThreadSanitizer (default)">; diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 47ef175302679f..291739e1221d96 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -64,6 +64,7 @@ class SanitizerArgs { // True if cross-dso CFI support if provided by the system (i.e. Android). bool ImplicitCfiRuntime = false; bool NeedsMemProfRt = false; + bool SanitizeOverflowIdioms = true; bool HwasanUseAliases = false; llvm::AsanDetectStackUseAfterReturnMode AsanUseAfterReturn = llvm::AsanDetectStackUseAfterReturnMode::Invalid; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 9d5b8167d0ee62..c07560c92100d7 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4759,6 +4759,54 @@ ParenListExpr *ParenListExpr::CreateEmpty(const ASTContext &Ctx, return new (Mem) ParenListExpr(EmptyShell(), NumExprs); } +namespace
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
JustinStitt wrote: @bwendling we want to use `-triple` not `-target`, can you cherry pick 3ef83ad323dfbe99028c774c3716706671ba7b8b I also reordered the tests and added labels so the tests are actually checking the right stuff -- debugging was really difficult but will be easier now. https://github.com/llvm/llvm-project/pull/100272 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Overflow Pattern Exclusions (PR #100272)
JustinStitt wrote: > Sorry, but I am not sure why this didn't show up my > https://github.com/llvm/llvm-project/pulls?q=is%3Aopen+is%3Apr+review-requested%3A%40me+sort%3Aupdated-desc > I wanted to review this patch. Did I do something wrong with my PR or fork settings? I am not sure why you weren't notified I left you on the CC and reviewer list. Thanks for your comments -- working on fixing the test cases right now. https://github.com/llvm/llvm-project/pull/100272 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/86618 >From 0fa8f07c722f9d7f80a90824f961ae6e9c5bdef7 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 5 Mar 2024 03:14:49 + Subject: [PATCH 1/4] implement wraps attribute Signed-off-by: Justin Stitt --- clang/docs/ReleaseNotes.rst | 7 ++ clang/include/clang/AST/Expr.h| 3 + clang/include/clang/Basic/Attr.td | 6 ++ clang/include/clang/Basic/AttrDocs.td | 66 +++ .../clang/Basic/DiagnosticSemaKinds.td| 3 + clang/include/clang/Sema/Sema.h | 4 ++ clang/lib/AST/Expr.cpp| 19 ++ clang/lib/AST/ExprConstant.cpp| 6 +- clang/lib/AST/TypePrinter.cpp | 3 + clang/lib/CodeGen/CGExprScalar.cpp| 40 +-- clang/lib/Sema/SemaDeclAttr.cpp | 12 +++- clang/lib/Sema/SemaType.cpp | 15 + clang/test/CodeGen/integer-overflow.c | 56 clang/test/CodeGen/unsigned-overflow.c| 63 +++--- clang/test/Sema/attr-wraps.c | 9 +++ 15 files changed, 296 insertions(+), 16 deletions(-) create mode 100644 clang/test/Sema/attr-wraps.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 7fbe2fec6ca065..20bb9815830592 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -248,6 +248,13 @@ Attribute Changes in Clang added a new extension query ``__has_extension(swiftcc)`` corresponding to the ``__attribute__((swiftcc))`` attribute. +- Introduced ``__attribute((wraps))`` or ``[[wraps]]`` which can be added to + type or variable declarations. Using an attributed type or variable in an + arithmetic expression will define the overflow behavior for that expression + as having two's complement wrap-around. These expressions cannot trigger + integer overflow warnings or sanitizer warnings. They also cannot be + optimized away by some eager UB optimizations. + Improvements to Clang's diagnostics --- - Clang now applies syntax highlighting to the code snippets it diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 6e153ebe024b42..934146e8a182bc 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -4084,6 +4084,9 @@ class BinaryOperator : public Expr { static unsigned sizeOfTrailingObjects(bool HasFPFeatures) { return HasFPFeatures * sizeof(FPOptionsOverride); } + + /// Do one of the subexpressions have the wraps attribute? + bool oneOfWraps(const ASTContext &Ctx) const; }; /// CompoundAssignOperator - For compound assignments (e.g. +=), we keep diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 3e03e55612645b..0ea7755791d82e 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4496,3 +4496,9 @@ def CodeAlign: StmtAttr { static constexpr int MaximumAlignment = 4096; }]; } + +def Wraps : DeclOrTypeAttr { + let Spellings = [Clang<"wraps">, CXX11<"", "wraps", 202403>]; + let Subjects = SubjectList<[Var, TypedefName, Field]>; + let Documentation = [WrapsDocs]; +} diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 9de14f608fd114..af662702edcffa 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8005,3 +8005,69 @@ requirement: } }]; } + +def WrapsDocs : Documentation { + let Category = DocCatField; + let Content = [{ +This attribute can be used with type or variable declarations to denote that +arithmetic containing these marked components have defined overflow behavior. +Specifically, the behavior is defined as being consistent with two's complement +wrap-around. For the purposes of sanitizers or warnings that concern themselves +with the definedness of integer arithmetic, they will cease to instrument or +warn about arithmetic that directly involves a "wrapping" component. + +For example, ``-fsanitize=signed-integer-overflow`` or ``-Winteger-overflow`` +will not warn about suspicious overflowing arithmetic -- assuming correct usage +of the wraps attribute. + +This example shows some basic usage of ``__attribute__((wraps))`` on a type +definition when building with ``-fsanitize=signed-integer-overflow`` + +.. code-block:: c + typedef int __attribute__((wraps)) wrapping_int; + + void foo() { +wrapping_int a = INT_MAX; +++a; // no sanitizer warning + } + + int main() { foo(); } + +In the following example, we use ``__attribute__((wraps))`` on a variable to +disable overflow instrumentation for arithmetic expressions it appears in. We +do so with a popular overflow-checking pattern which we might not want to trip +sanitizers (like ``-fsanitize=unsigned-integer-overflow``). + +.. code-block:: c + void foo(int offset)
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/86618 >From 10ee32826fc2acb6bd993c88bdb7142360b6f263 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 5 Mar 2024 03:14:49 + Subject: [PATCH 1/3] implement wraps attribute Signed-off-by: Justin Stitt --- clang/docs/ReleaseNotes.rst | 9 +++ clang/include/clang/AST/Expr.h| 3 + clang/include/clang/Basic/Attr.td | 6 ++ clang/include/clang/Basic/AttrDocs.td | 66 +++ .../clang/Basic/DiagnosticSemaKinds.td| 3 + clang/include/clang/Sema/Sema.h | 4 ++ clang/lib/AST/Expr.cpp| 19 ++ clang/lib/AST/ExprConstant.cpp| 6 +- clang/lib/AST/TypePrinter.cpp | 3 + clang/lib/CodeGen/CGExprScalar.cpp| 40 +-- clang/lib/Sema/SemaDeclAttr.cpp | 12 +++- clang/lib/Sema/SemaType.cpp | 15 + clang/test/CodeGen/integer-overflow.c | 56 clang/test/CodeGen/unsigned-overflow.c| 63 +++--- clang/test/Sema/attr-wraps.c | 9 +++ 15 files changed, 298 insertions(+), 16 deletions(-) create mode 100644 clang/test/Sema/attr-wraps.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f96cebbde3d825..cb02af7e948989 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -282,6 +282,15 @@ Attribute Changes in Clang This allows the ``_Nullable`` and ``_Nonnull`` family of type attributes to apply to this class. +- Introduced ``__attribute((wraps))__`` which can be added to type or variable + declarations. Using an attributed type or variable in an arithmetic + expression will define the overflow behavior for that expression as having + two's complement wrap-around. These expressions cannot trigger integer + overflow warnings or sanitizer warnings. They also cannot be optimized away + by some eager UB optimizations. + + This attribute is ignored in C++. + Improvements to Clang's diagnostics --- - Clang now applies syntax highlighting to the code snippets it diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 2bfefeabc348be..68cd7d7c0fac3b 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -4077,6 +4077,9 @@ class BinaryOperator : public Expr { static unsigned sizeOfTrailingObjects(bool HasFPFeatures) { return HasFPFeatures * sizeof(FPOptionsOverride); } + + /// Do one of the subexpressions have the wraps attribute? + bool oneOfWraps(const ASTContext &Ctx) const; }; /// CompoundAssignOperator - For compound assignments (e.g. +=), we keep diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index dc87a8c6f022dc..06e41fcee206c4 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4506,3 +4506,9 @@ def CodeAlign: StmtAttr { static constexpr int MaximumAlignment = 4096; }]; } + +def Wraps : DeclOrTypeAttr { + let Spellings = [Clang<"wraps">, CXX11<"", "wraps", 202403>]; + let Subjects = SubjectList<[Var, TypedefName, Field]>; + let Documentation = [WrapsDocs]; +} diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 0ca4ea377fc36a..a2adb923e3c47c 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8044,3 +8044,69 @@ requirement: } }]; } + +def WrapsDocs : Documentation { + let Category = DocCatField; + let Content = [{ +This attribute can be used with type or variable declarations to denote that +arithmetic containing these marked components have defined overflow behavior. +Specifically, the behavior is defined as being consistent with two's complement +wrap-around. For the purposes of sanitizers or warnings that concern themselves +with the definedness of integer arithmetic, they will cease to instrument or +warn about arithmetic that directly involves a "wrapping" component. + +For example, ``-fsanitize=signed-integer-overflow`` or ``-Winteger-overflow`` +will not warn about suspicious overflowing arithmetic -- assuming correct usage +of the wraps attribute. + +This example shows some basic usage of ``__attribute__((wraps))`` on a type +definition when building with ``-fsanitize=signed-integer-overflow`` + +.. code-block:: c + typedef int __attribute__((wraps)) wrapping_int; + + void foo() { +wrapping_int a = INT_MAX; +++a; // no sanitizer warning + } + + int main() { foo(); } + +In the following example, we use ``__attribute__((wraps))`` on a variable to +disable overflow instrumentation for arithmetic expressions it appears in. We +do so with a popular overflow-checking pattern which we might not want to trip +sanitizers (like ``-fsanitize=unsigned-integer-overflow``). + +.. code-block:: c + void foo(int off
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
JustinStitt wrote: Hi, I've made some changes and am looking for some more review on this PR: * This attribute no longer supports C++ as there are other solutions for that language [1] that allow for the same fine-grained wrapping control without changing syntax patterns. * Add bypass for implicit-(un)signed-integer-truncation sanitizers * Rebased onto eec41d2f8d81b546d7b97648cca6b2d656104bd3 [1]: https://godbolt.org/z/7qPve6cWq (simple example) https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
https://github.com/JustinStitt edited https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/86618 >From 10ee32826fc2acb6bd993c88bdb7142360b6f263 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 5 Mar 2024 03:14:49 + Subject: [PATCH 1/4] implement wraps attribute Signed-off-by: Justin Stitt --- clang/docs/ReleaseNotes.rst | 9 +++ clang/include/clang/AST/Expr.h| 3 + clang/include/clang/Basic/Attr.td | 6 ++ clang/include/clang/Basic/AttrDocs.td | 66 +++ .../clang/Basic/DiagnosticSemaKinds.td| 3 + clang/include/clang/Sema/Sema.h | 4 ++ clang/lib/AST/Expr.cpp| 19 ++ clang/lib/AST/ExprConstant.cpp| 6 +- clang/lib/AST/TypePrinter.cpp | 3 + clang/lib/CodeGen/CGExprScalar.cpp| 40 +-- clang/lib/Sema/SemaDeclAttr.cpp | 12 +++- clang/lib/Sema/SemaType.cpp | 15 + clang/test/CodeGen/integer-overflow.c | 56 clang/test/CodeGen/unsigned-overflow.c| 63 +++--- clang/test/Sema/attr-wraps.c | 9 +++ 15 files changed, 298 insertions(+), 16 deletions(-) create mode 100644 clang/test/Sema/attr-wraps.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f96cebbde3d825..cb02af7e948989 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -282,6 +282,15 @@ Attribute Changes in Clang This allows the ``_Nullable`` and ``_Nonnull`` family of type attributes to apply to this class. +- Introduced ``__attribute((wraps))__`` which can be added to type or variable + declarations. Using an attributed type or variable in an arithmetic + expression will define the overflow behavior for that expression as having + two's complement wrap-around. These expressions cannot trigger integer + overflow warnings or sanitizer warnings. They also cannot be optimized away + by some eager UB optimizations. + + This attribute is ignored in C++. + Improvements to Clang's diagnostics --- - Clang now applies syntax highlighting to the code snippets it diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 2bfefeabc348be..68cd7d7c0fac3b 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -4077,6 +4077,9 @@ class BinaryOperator : public Expr { static unsigned sizeOfTrailingObjects(bool HasFPFeatures) { return HasFPFeatures * sizeof(FPOptionsOverride); } + + /// Do one of the subexpressions have the wraps attribute? + bool oneOfWraps(const ASTContext &Ctx) const; }; /// CompoundAssignOperator - For compound assignments (e.g. +=), we keep diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index dc87a8c6f022dc..06e41fcee206c4 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4506,3 +4506,9 @@ def CodeAlign: StmtAttr { static constexpr int MaximumAlignment = 4096; }]; } + +def Wraps : DeclOrTypeAttr { + let Spellings = [Clang<"wraps">, CXX11<"", "wraps", 202403>]; + let Subjects = SubjectList<[Var, TypedefName, Field]>; + let Documentation = [WrapsDocs]; +} diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 0ca4ea377fc36a..a2adb923e3c47c 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8044,3 +8044,69 @@ requirement: } }]; } + +def WrapsDocs : Documentation { + let Category = DocCatField; + let Content = [{ +This attribute can be used with type or variable declarations to denote that +arithmetic containing these marked components have defined overflow behavior. +Specifically, the behavior is defined as being consistent with two's complement +wrap-around. For the purposes of sanitizers or warnings that concern themselves +with the definedness of integer arithmetic, they will cease to instrument or +warn about arithmetic that directly involves a "wrapping" component. + +For example, ``-fsanitize=signed-integer-overflow`` or ``-Winteger-overflow`` +will not warn about suspicious overflowing arithmetic -- assuming correct usage +of the wraps attribute. + +This example shows some basic usage of ``__attribute__((wraps))`` on a type +definition when building with ``-fsanitize=signed-integer-overflow`` + +.. code-block:: c + typedef int __attribute__((wraps)) wrapping_int; + + void foo() { +wrapping_int a = INT_MAX; +++a; // no sanitizer warning + } + + int main() { foo(); } + +In the following example, we use ``__attribute__((wraps))`` on a variable to +disable overflow instrumentation for arithmetic expressions it appears in. We +do so with a popular overflow-checking pattern which we might not want to trip +sanitizers (like ``-fsanitize=unsigned-integer-overflow``). + +.. code-block:: c + void foo(int off
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/86618 >From 10ee32826fc2acb6bd993c88bdb7142360b6f263 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 5 Mar 2024 03:14:49 + Subject: [PATCH 1/7] implement wraps attribute Signed-off-by: Justin Stitt --- clang/docs/ReleaseNotes.rst | 9 +++ clang/include/clang/AST/Expr.h| 3 + clang/include/clang/Basic/Attr.td | 6 ++ clang/include/clang/Basic/AttrDocs.td | 66 +++ .../clang/Basic/DiagnosticSemaKinds.td| 3 + clang/include/clang/Sema/Sema.h | 4 ++ clang/lib/AST/Expr.cpp| 19 ++ clang/lib/AST/ExprConstant.cpp| 6 +- clang/lib/AST/TypePrinter.cpp | 3 + clang/lib/CodeGen/CGExprScalar.cpp| 40 +-- clang/lib/Sema/SemaDeclAttr.cpp | 12 +++- clang/lib/Sema/SemaType.cpp | 15 + clang/test/CodeGen/integer-overflow.c | 56 clang/test/CodeGen/unsigned-overflow.c| 63 +++--- clang/test/Sema/attr-wraps.c | 9 +++ 15 files changed, 298 insertions(+), 16 deletions(-) create mode 100644 clang/test/Sema/attr-wraps.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f96cebbde3d825..cb02af7e948989 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -282,6 +282,15 @@ Attribute Changes in Clang This allows the ``_Nullable`` and ``_Nonnull`` family of type attributes to apply to this class. +- Introduced ``__attribute((wraps))__`` which can be added to type or variable + declarations. Using an attributed type or variable in an arithmetic + expression will define the overflow behavior for that expression as having + two's complement wrap-around. These expressions cannot trigger integer + overflow warnings or sanitizer warnings. They also cannot be optimized away + by some eager UB optimizations. + + This attribute is ignored in C++. + Improvements to Clang's diagnostics --- - Clang now applies syntax highlighting to the code snippets it diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 2bfefeabc348be..68cd7d7c0fac3b 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -4077,6 +4077,9 @@ class BinaryOperator : public Expr { static unsigned sizeOfTrailingObjects(bool HasFPFeatures) { return HasFPFeatures * sizeof(FPOptionsOverride); } + + /// Do one of the subexpressions have the wraps attribute? + bool oneOfWraps(const ASTContext &Ctx) const; }; /// CompoundAssignOperator - For compound assignments (e.g. +=), we keep diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index dc87a8c6f022dc..06e41fcee206c4 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4506,3 +4506,9 @@ def CodeAlign: StmtAttr { static constexpr int MaximumAlignment = 4096; }]; } + +def Wraps : DeclOrTypeAttr { + let Spellings = [Clang<"wraps">, CXX11<"", "wraps", 202403>]; + let Subjects = SubjectList<[Var, TypedefName, Field]>; + let Documentation = [WrapsDocs]; +} diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 0ca4ea377fc36a..a2adb923e3c47c 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8044,3 +8044,69 @@ requirement: } }]; } + +def WrapsDocs : Documentation { + let Category = DocCatField; + let Content = [{ +This attribute can be used with type or variable declarations to denote that +arithmetic containing these marked components have defined overflow behavior. +Specifically, the behavior is defined as being consistent with two's complement +wrap-around. For the purposes of sanitizers or warnings that concern themselves +with the definedness of integer arithmetic, they will cease to instrument or +warn about arithmetic that directly involves a "wrapping" component. + +For example, ``-fsanitize=signed-integer-overflow`` or ``-Winteger-overflow`` +will not warn about suspicious overflowing arithmetic -- assuming correct usage +of the wraps attribute. + +This example shows some basic usage of ``__attribute__((wraps))`` on a type +definition when building with ``-fsanitize=signed-integer-overflow`` + +.. code-block:: c + typedef int __attribute__((wraps)) wrapping_int; + + void foo() { +wrapping_int a = INT_MAX; +++a; // no sanitizer warning + } + + int main() { foo(); } + +In the following example, we use ``__attribute__((wraps))`` on a variable to +disable overflow instrumentation for arithmetic expressions it appears in. We +do so with a popular overflow-checking pattern which we might not want to trip +sanitizers (like ``-fsanitize=unsigned-integer-overflow``). + +.. code-block:: c + void foo(int off
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
@@ -4077,6 +4077,9 @@ class BinaryOperator : public Expr { static unsigned sizeOfTrailingObjects(bool HasFPFeatures) { return HasFPFeatures * sizeof(FPOptionsOverride); } + + /// Do one of the subexpressions have the wraps attribute? + bool oneOfWraps(const ASTContext &Ctx) const; JustinStitt wrote: Hi, fixed with 5e6d926532c2cff3288f25e9b8f872e7f2ec9b65 https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
@@ -4506,3 +4506,9 @@ def CodeAlign: StmtAttr { static constexpr int MaximumAlignment = 4096; }]; } + +def Wraps : DeclOrTypeAttr { + let Spellings = [GNU<"wraps">]; JustinStitt wrote: Right, I had that originally. I shouldn't have changed it :) Anyways, fixed in 0d7566777f06b3f2058d93dd77624ab2c66f1127 https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
@@ -4506,3 +4506,9 @@ def CodeAlign: StmtAttr { static constexpr int MaximumAlignment = 4096; }]; } + +def Wraps : DeclOrTypeAttr { + let Spellings = [GNU<"wraps">]; + let Subjects = SubjectList<[Var, TypedefName, Field]>; + let Documentation = [WrapsDocs]; +} JustinStitt wrote: 0d7566777f06b3f2058d93dd77624ab2c66f1127 https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
@@ -2237,6 +2237,21 @@ bool BinaryOperator::isNullPointerArithmeticExtension(ASTContext &Ctx, return true; } +bool BinaryOperator::oneOfWraps(const ASTContext &Ctx) const { + llvm::SmallVector Both = {getLHS(), getRHS()}; JustinStitt wrote: I had trouble with your code snippet because `children()` gives `Stmt` iterators and I would have to add in a cast or two. I went with a simpler approach in a2f63982920f22d795c4971800bcc5cb55356570 (with QualType::hasWrapsAttr()) https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
@@ -147,6 +147,15 @@ struct BinOpInfo { return UnOp->getSubExpr()->getType()->isFixedPointType(); return false; } + + /// Does the BinaryOperator have the wraps attribute? + /// If so, we can ellide overflow sanitizer checks. + bool oneOfWraps() const { +const Type *TyPtr = E->getType().getTypePtrOrNull(); +if (TyPtr) JustinStitt wrote: Gotcha, checkout a2f63982920f22d795c4971800bcc5cb55356570 https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
@@ -6954,6 +6954,23 @@ static void HandleBTFTypeTagAttribute(QualType &Type, const ParsedAttr &Attr, ::new (Ctx) BTFTypeTagAttr(Ctx, Attr, BTFTypeTag), Type); } +static void handleWrapsAttr(QualType &Type, const ParsedAttr &Attr, +TypeProcessingState &State) { + Sema &S = State.getSema(); + ASTContext &Ctx = S.Context; + + // No need to warn here, that is handled by SemaDeclAttr. + // Simply disable applying this attribute. + if (S.getLangOpts().CPlusPlus) JustinStitt wrote: Right! I missed this. Fixed! https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/86618 >From 10ee32826fc2acb6bd993c88bdb7142360b6f263 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 5 Mar 2024 03:14:49 + Subject: [PATCH 1/8] implement wraps attribute Signed-off-by: Justin Stitt --- clang/docs/ReleaseNotes.rst | 9 +++ clang/include/clang/AST/Expr.h| 3 + clang/include/clang/Basic/Attr.td | 6 ++ clang/include/clang/Basic/AttrDocs.td | 66 +++ .../clang/Basic/DiagnosticSemaKinds.td| 3 + clang/include/clang/Sema/Sema.h | 4 ++ clang/lib/AST/Expr.cpp| 19 ++ clang/lib/AST/ExprConstant.cpp| 6 +- clang/lib/AST/TypePrinter.cpp | 3 + clang/lib/CodeGen/CGExprScalar.cpp| 40 +-- clang/lib/Sema/SemaDeclAttr.cpp | 12 +++- clang/lib/Sema/SemaType.cpp | 15 + clang/test/CodeGen/integer-overflow.c | 56 clang/test/CodeGen/unsigned-overflow.c| 63 +++--- clang/test/Sema/attr-wraps.c | 9 +++ 15 files changed, 298 insertions(+), 16 deletions(-) create mode 100644 clang/test/Sema/attr-wraps.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f96cebbde3d825..cb02af7e948989 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -282,6 +282,15 @@ Attribute Changes in Clang This allows the ``_Nullable`` and ``_Nonnull`` family of type attributes to apply to this class. +- Introduced ``__attribute((wraps))__`` which can be added to type or variable + declarations. Using an attributed type or variable in an arithmetic + expression will define the overflow behavior for that expression as having + two's complement wrap-around. These expressions cannot trigger integer + overflow warnings or sanitizer warnings. They also cannot be optimized away + by some eager UB optimizations. + + This attribute is ignored in C++. + Improvements to Clang's diagnostics --- - Clang now applies syntax highlighting to the code snippets it diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 2bfefeabc348be..68cd7d7c0fac3b 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -4077,6 +4077,9 @@ class BinaryOperator : public Expr { static unsigned sizeOfTrailingObjects(bool HasFPFeatures) { return HasFPFeatures * sizeof(FPOptionsOverride); } + + /// Do one of the subexpressions have the wraps attribute? + bool oneOfWraps(const ASTContext &Ctx) const; }; /// CompoundAssignOperator - For compound assignments (e.g. +=), we keep diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index dc87a8c6f022dc..06e41fcee206c4 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4506,3 +4506,9 @@ def CodeAlign: StmtAttr { static constexpr int MaximumAlignment = 4096; }]; } + +def Wraps : DeclOrTypeAttr { + let Spellings = [Clang<"wraps">, CXX11<"", "wraps", 202403>]; + let Subjects = SubjectList<[Var, TypedefName, Field]>; + let Documentation = [WrapsDocs]; +} diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 0ca4ea377fc36a..a2adb923e3c47c 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8044,3 +8044,69 @@ requirement: } }]; } + +def WrapsDocs : Documentation { + let Category = DocCatField; + let Content = [{ +This attribute can be used with type or variable declarations to denote that +arithmetic containing these marked components have defined overflow behavior. +Specifically, the behavior is defined as being consistent with two's complement +wrap-around. For the purposes of sanitizers or warnings that concern themselves +with the definedness of integer arithmetic, they will cease to instrument or +warn about arithmetic that directly involves a "wrapping" component. + +For example, ``-fsanitize=signed-integer-overflow`` or ``-Winteger-overflow`` +will not warn about suspicious overflowing arithmetic -- assuming correct usage +of the wraps attribute. + +This example shows some basic usage of ``__attribute__((wraps))`` on a type +definition when building with ``-fsanitize=signed-integer-overflow`` + +.. code-block:: c + typedef int __attribute__((wraps)) wrapping_int; + + void foo() { +wrapping_int a = INT_MAX; +++a; // no sanitizer warning + } + + int main() { foo(); } + +In the following example, we use ``__attribute__((wraps))`` on a variable to +disable overflow instrumentation for arithmetic expressions it appears in. We +do so with a popular overflow-checking pattern which we might not want to trip +sanitizers (like ``-fsanitize=unsigned-integer-overflow``). + +.. code-block:: c + void foo(int off
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
JustinStitt wrote: The most recent commits have massively simplified checking for the wrapping attributes. FWIW, the tests I am running are: ✅ `$ llvm-lit clang/test/CodeGen/integer-overflow.c -v` ✅ `$ llvm-lit clang/test/CodeGen/unsigned-overflow.c -v` ✅ `$ llvm-lit clang/test/Sema/attr-wraps.c -v` ...and some hand-rolled stuff I have. https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
https://github.com/JustinStitt updated https://github.com/llvm/llvm-project/pull/86618 >From 10ee32826fc2acb6bd993c88bdb7142360b6f263 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 5 Mar 2024 03:14:49 + Subject: [PATCH 1/9] implement wraps attribute Signed-off-by: Justin Stitt --- clang/docs/ReleaseNotes.rst | 9 +++ clang/include/clang/AST/Expr.h| 3 + clang/include/clang/Basic/Attr.td | 6 ++ clang/include/clang/Basic/AttrDocs.td | 66 +++ .../clang/Basic/DiagnosticSemaKinds.td| 3 + clang/include/clang/Sema/Sema.h | 4 ++ clang/lib/AST/Expr.cpp| 19 ++ clang/lib/AST/ExprConstant.cpp| 6 +- clang/lib/AST/TypePrinter.cpp | 3 + clang/lib/CodeGen/CGExprScalar.cpp| 40 +-- clang/lib/Sema/SemaDeclAttr.cpp | 12 +++- clang/lib/Sema/SemaType.cpp | 15 + clang/test/CodeGen/integer-overflow.c | 56 clang/test/CodeGen/unsigned-overflow.c| 63 +++--- clang/test/Sema/attr-wraps.c | 9 +++ 15 files changed, 298 insertions(+), 16 deletions(-) create mode 100644 clang/test/Sema/attr-wraps.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f96cebbde3d825..cb02af7e948989 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -282,6 +282,15 @@ Attribute Changes in Clang This allows the ``_Nullable`` and ``_Nonnull`` family of type attributes to apply to this class. +- Introduced ``__attribute((wraps))__`` which can be added to type or variable + declarations. Using an attributed type or variable in an arithmetic + expression will define the overflow behavior for that expression as having + two's complement wrap-around. These expressions cannot trigger integer + overflow warnings or sanitizer warnings. They also cannot be optimized away + by some eager UB optimizations. + + This attribute is ignored in C++. + Improvements to Clang's diagnostics --- - Clang now applies syntax highlighting to the code snippets it diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 2bfefeabc348be..68cd7d7c0fac3b 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -4077,6 +4077,9 @@ class BinaryOperator : public Expr { static unsigned sizeOfTrailingObjects(bool HasFPFeatures) { return HasFPFeatures * sizeof(FPOptionsOverride); } + + /// Do one of the subexpressions have the wraps attribute? + bool oneOfWraps(const ASTContext &Ctx) const; }; /// CompoundAssignOperator - For compound assignments (e.g. +=), we keep diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index dc87a8c6f022dc..06e41fcee206c4 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4506,3 +4506,9 @@ def CodeAlign: StmtAttr { static constexpr int MaximumAlignment = 4096; }]; } + +def Wraps : DeclOrTypeAttr { + let Spellings = [Clang<"wraps">, CXX11<"", "wraps", 202403>]; + let Subjects = SubjectList<[Var, TypedefName, Field]>; + let Documentation = [WrapsDocs]; +} diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 0ca4ea377fc36a..a2adb923e3c47c 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8044,3 +8044,69 @@ requirement: } }]; } + +def WrapsDocs : Documentation { + let Category = DocCatField; + let Content = [{ +This attribute can be used with type or variable declarations to denote that +arithmetic containing these marked components have defined overflow behavior. +Specifically, the behavior is defined as being consistent with two's complement +wrap-around. For the purposes of sanitizers or warnings that concern themselves +with the definedness of integer arithmetic, they will cease to instrument or +warn about arithmetic that directly involves a "wrapping" component. + +For example, ``-fsanitize=signed-integer-overflow`` or ``-Winteger-overflow`` +will not warn about suspicious overflowing arithmetic -- assuming correct usage +of the wraps attribute. + +This example shows some basic usage of ``__attribute__((wraps))`` on a type +definition when building with ``-fsanitize=signed-integer-overflow`` + +.. code-block:: c + typedef int __attribute__((wraps)) wrapping_int; + + void foo() { +wrapping_int a = INT_MAX; +++a; // no sanitizer warning + } + + int main() { foo(); } + +In the following example, we use ``__attribute__((wraps))`` on a variable to +disable overflow instrumentation for arithmetic expressions it appears in. We +do so with a popular overflow-checking pattern which we might not want to trip +sanitizers (like ``-fsanitize=unsigned-integer-overflow``). + +.. code-block:: c + void foo(int off
[clang] [Clang] Add wraps attribute (for granular integer overflow handling) (PR #86618)
JustinStitt wrote: > > Forbidding usage in C++ probably avoids the worst of the canonical-type > > issues, but there's still some potential for weird results. Particularly > > with type merging; for example, if you write `a ? (wrap_int)x : 1`, is the > > result a wrapping type? > > I had a similar question in the general case: is the annotation contagious? > > ``` > int foo(wrap_int x, int a, int b, int c) { > if (x + a + b < c) > return 0; > return 1; > } > ``` > > The `x + a` is checked, but is that result checked when added to `b`? Yes, it's "contagious": ``` |-FunctionDecl 0x55f64065a5d8 line:6:5 foo 'int (wrap_int, int, int, int)' | |-ParmVarDecl 0x55f64065a300 col:18 used x 'wrap_int':'int' | |-ParmVarDecl 0x55f64065a380 col:25 used a 'int' | |-ParmVarDecl 0x55f64065a400 col:32 used b 'int' | |-ParmVarDecl 0x55f64065a480 col:39 used c 'int' | `-CompoundStmt 0x55f64065a8a8 | |-IfStmt 0x55f64065a858 | | |-BinaryOperator 0x55f64065a808 'int __attribute__((wraps))':'int' '<' | | | |-BinaryOperator 0x55f64065a7b0 'int __attribute__((wraps))':'int' '+' | | | | |-BinaryOperator 0x55f64065a758 'int __attribute__((wraps))':'int' '+' | | | | | |-ImplicitCastExpr 0x55f64065a728 'wrap_int':'int' | | | | | | `-DeclRefExpr 0x55f64065a6e8 'wrap_int':'int' lvalue ParmVar 0x55f64065a300 'x' 'wrap_int':'int' | | | | | `-ImplicitCastExpr 0x55f64065a740 'int' | | | | | `-DeclRefExpr 0x55f64065a708 'int' lvalue ParmVar 0x55f64065a380 'a' 'int' | | | | `-ImplicitCastExpr 0x55f64065a798 'int' | | | | `-DeclRefExpr 0x55f64065a778 'int' lvalue ParmVar 0x55f64065a400 'b' 'int' | | | `-ImplicitCastExpr 0x55f64065a7f0 'int' | | | `-DeclRefExpr 0x55f64065a7d0 'int' lvalue ParmVar 0x55f64065a480 'c' 'int' | | `-ReturnStmt 0x55f64065a848 | | `-IntegerLiteral 0x55f64065a828 'int' 0 | `-ReturnStmt 0x55f64065a898 | `-IntegerLiteral 0x55f64065a878 'int' 1 ``` https://github.com/llvm/llvm-project/pull/86618 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits