-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[Clang] Add -fwrapv-pointer flag #122486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Clang] Add -fwrapv-pointer flag #122486
Conversation
@llvm/pr-subscribers-clang-codegen @llvm/pr-subscribers-clang-driver Author: Nikita Popov (nikic) ChangesGCC supports three flags related to overflow behavior:
Clang currently only supports This PR proposes to introduce This allows signed integer overflow and pointer overflow to be controlled independently, while Full diff: https://github.com/llvm/llvm-project/pull/122486.diff 13 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 511a28c5554bbb..44d98d98411d12 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -58,6 +58,12 @@ code bases.
containing strict-aliasing violations. The new default behavior can be
disabled using ``-fno-pointer-tbaa``.
+- The ``-fwrapv`` flag now only makes signed integer overflow well-defined,
+ without affecting pointer overflow, which is controlled by a new
+ ``-fwrapv-pointer`` flag. The ``-fno-strict-overflow`` flag now implies
+ both ``-fwrapv`` and ``-fwrapv-pointer`` and as such retains its old meaning.
+ The new behavior matches GCC.
+
C/C++ Language Potentially Breaking Changes
-------------------------------------------
@@ -464,6 +470,11 @@ New Compiler Flags
- clang-cl and clang-dxc now support ``-fdiagnostics-color=[auto|never|always]``
in addition to ``-f[no-]color-diagnostics``.
+- The new ``-fwrapv-pointer`` flag opts-in to a language dialect where pointer
+ overflow is well-defined. The ``-fwrapv`` flag previously implied
+ ``-fwrapv-pointer`` as well, but no longer does. ``-fno-strict-overflow``
+ implies ``-fwrapv -fwrapv-pointer``. The flags now match GCC.
+
Deprecated Compiler Flags
-------------------------
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 3b833240e5b68c..c4c53d7455c417 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -407,6 +407,7 @@ 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(PointerOverflowDefined, 1, 0, "make pointer overflow defined")
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 41a7e8c3728066..8b45aa6dd4c2df 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4291,6 +4291,11 @@ def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>,
HelpText<"Treat signed integer overflow as two's complement">;
def fno_wrapv : Flag<["-"], "fno-wrapv">, Group<f_Group>,
Visibility<[ClangOption, CLOption, FlangOption]>;
+def fwrapv_pointer : Flag<["-"], "fwrapv-pointer">, Group<f_Group>,
+ Visibility<[ClangOption, CLOption, CC1Option, FlangOption, FC1Option]>,
+ HelpText<"Treat pointer overflow as two's complement">;
+def fno_wrapv_pointer : Flag<["-"], "fno-wrapv-pointer">, Group<f_Group>,
+ Visibility<[ClangOption, CLOption, FlangOption]>;
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Store string literals as writable data">,
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index ca03fb665d423d..b5bbfeae576029 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -22113,7 +22113,7 @@ RValue CodeGenFunction::EmitBuiltinAlignTo(const CallExpr *E, bool AlignUp) {
// By adding the mask, we ensure that align_up on an already aligned
// value will not change the value.
if (Args.Src->getType()->isPointerTy()) {
- if (getLangOpts().isSignedOverflowDefined())
+ if (getLangOpts().PointerOverflowDefined)
SrcForMask =
Builder.CreateGEP(Int8Ty, SrcForMask, Args.Mask, "over_boundary");
else
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 1bad7a722da07a..dc9c2afeaa93a5 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4307,14 +4307,14 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
// GEP indexes are signed, and scaling an index isn't permitted to
// signed-overflow, so we use the same semantics for our explicit
// multiply. We suppress this if overflow is not undefined behavior.
- if (getLangOpts().isSignedOverflowDefined()) {
+ if (getLangOpts().PointerOverflowDefined) {
Idx = Builder.CreateMul(Idx, numElements);
} else {
Idx = Builder.CreateNSWMul(Idx, numElements);
}
Addr = emitArraySubscriptGEP(*this, Addr, Idx, vla->getElementType(),
- !getLangOpts().isSignedOverflowDefined(),
+ !getLangOpts().PointerOverflowDefined,
SignedIndices, E->getExprLoc());
} else if (const ObjCObjectType *OIT = E->getType()->getAs<ObjCObjectType>()){
@@ -4404,7 +4404,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
QualType arrayType = Array->getType();
Addr = emitArraySubscriptGEP(
*this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
- E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices,
+ E->getType(), !getLangOpts().PointerOverflowDefined, SignedIndices,
E->getExprLoc(), &arrayType, E->getBase());
EltBaseInfo = ArrayLV.getBaseInfo();
EltTBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, E->getType());
@@ -4414,7 +4414,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
QualType ptrType = E->getBase()->getType();
Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(),
- !getLangOpts().isSignedOverflowDefined(),
+ !getLangOpts().PointerOverflowDefined,
SignedIndices, E->getExprLoc(), &ptrType,
E->getBase());
}
@@ -4561,11 +4561,11 @@ LValue CodeGenFunction::EmitArraySectionExpr(const ArraySectionExpr *E,
: llvm::ConstantInt::get(IntPtrTy, ConstLength);
Idx = Builder.CreateAdd(LowerBoundVal, LengthVal, "lb_add_len",
/*HasNUW=*/false,
- !getLangOpts().isSignedOverflowDefined());
+ !getLangOpts().PointerOverflowDefined);
if (Length && LowerBound) {
Idx = Builder.CreateSub(
Idx, llvm::ConstantInt::get(IntPtrTy, /*V=*/1), "idx_sub_1",
- /*HasNUW=*/false, !getLangOpts().isSignedOverflowDefined());
+ /*HasNUW=*/false, !getLangOpts().PointerOverflowDefined);
}
} else
Idx = llvm::ConstantInt::get(IntPtrTy, ConstLength + ConstLowerBound);
@@ -4591,7 +4591,7 @@ LValue CodeGenFunction::EmitArraySectionExpr(const ArraySectionExpr *E,
Length->getType()->hasSignedIntegerRepresentation());
Idx = Builder.CreateSub(
LengthVal, llvm::ConstantInt::get(IntPtrTy, /*V=*/1), "len_sub_1",
- /*HasNUW=*/false, !getLangOpts().isSignedOverflowDefined());
+ /*HasNUW=*/false, !getLangOpts().PointerOverflowDefined);
} else {
ConstLength = ConstLength.zextOrTrunc(PointerWidthInBits);
--ConstLength;
@@ -4618,12 +4618,12 @@ LValue CodeGenFunction::EmitArraySectionExpr(const ArraySectionExpr *E,
// GEP indexes are signed, and scaling an index isn't permitted to
// signed-overflow, so we use the same semantics for our explicit
// multiply. We suppress this if overflow is not undefined behavior.
- if (getLangOpts().isSignedOverflowDefined())
+ if (getLangOpts().PointerOverflowDefined)
Idx = Builder.CreateMul(Idx, NumElements);
else
Idx = Builder.CreateNSWMul(Idx, NumElements);
EltPtr = emitArraySubscriptGEP(*this, Base, Idx, VLA->getElementType(),
- !getLangOpts().isSignedOverflowDefined(),
+ !getLangOpts().PointerOverflowDefined,
/*signedIndices=*/false, E->getExprLoc());
} else if (const Expr *Array = isSimpleArrayDecayOperand(E->getBase())) {
// If this is A[i] where A is an array, the frontend will have decayed the
@@ -4643,7 +4643,7 @@ LValue CodeGenFunction::EmitArraySectionExpr(const ArraySectionExpr *E,
// Propagate the alignment from the array itself to the result.
EltPtr = emitArraySubscriptGEP(
*this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
- ResultExprTy, !getLangOpts().isSignedOverflowDefined(),
+ ResultExprTy, !getLangOpts().PointerOverflowDefined,
/*signedIndices=*/false, E->getExprLoc());
BaseInfo = ArrayLV.getBaseInfo();
TBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, ResultExprTy);
@@ -4652,7 +4652,7 @@ LValue CodeGenFunction::EmitArraySectionExpr(const ArraySectionExpr *E,
emitOMPArraySectionBase(*this, E->getBase(), BaseInfo, TBAAInfo, BaseTy,
ResultExprTy, IsLowerBound);
EltPtr = emitArraySubscriptGEP(*this, Base, Idx, ResultExprTy,
- !getLangOpts().isSignedOverflowDefined(),
+ !getLangOpts().PointerOverflowDefined,
/*signedIndices=*/false, E->getExprLoc());
}
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 090c4fb3ea39ee..32395391000ffb 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -3037,7 +3037,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::Value *numElts = CGF.getVLASize(vla).NumElts;
if (!isInc) numElts = Builder.CreateNSWNeg(numElts, "vla.negsize");
llvm::Type *elemTy = CGF.ConvertTypeForMem(vla->getElementType());
- if (CGF.getLangOpts().isSignedOverflowDefined())
+ if (CGF.getLangOpts().PointerOverflowDefined)
value = Builder.CreateGEP(elemTy, value, numElts, "vla.inc");
else
value = CGF.EmitCheckedInBoundsGEP(
@@ -3048,7 +3048,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
} else if (type->isFunctionType()) {
llvm::Value *amt = Builder.getInt32(amount);
- if (CGF.getLangOpts().isSignedOverflowDefined())
+ if (CGF.getLangOpts().PointerOverflowDefined)
value = Builder.CreateGEP(CGF.Int8Ty, value, amt, "incdec.funcptr");
else
value =
@@ -3060,7 +3060,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
} else {
llvm::Value *amt = Builder.getInt32(amount);
llvm::Type *elemTy = CGF.ConvertTypeForMem(type);
- if (CGF.getLangOpts().isSignedOverflowDefined())
+ if (CGF.getLangOpts().PointerOverflowDefined)
value = Builder.CreateGEP(elemTy, value, amt, "incdec.ptr");
else
value = CGF.EmitCheckedInBoundsGEP(
@@ -3173,7 +3173,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::Value *sizeValue =
llvm::ConstantInt::get(CGF.SizeTy, size.getQuantity());
- if (CGF.getLangOpts().isSignedOverflowDefined())
+ if (CGF.getLangOpts().PointerOverflowDefined)
value = Builder.CreateGEP(CGF.Int8Ty, value, sizeValue, "incdec.objptr");
else
value = CGF.EmitCheckedInBoundsGEP(
@@ -4067,7 +4067,7 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
// signed-overflow, so we use the same semantics for our explicit
// multiply. We suppress this if overflow is not undefined behavior.
llvm::Type *elemTy = CGF.ConvertTypeForMem(vla->getElementType());
- if (CGF.getLangOpts().isSignedOverflowDefined()) {
+ if (CGF.getLangOpts().PointerOverflowDefined) {
index = CGF.Builder.CreateMul(index, numElements, "vla.index");
pointer = CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
} else {
@@ -4088,7 +4088,7 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
else
elemTy = CGF.ConvertTypeForMem(elementType);
- if (CGF.getLangOpts().isSignedOverflowDefined())
+ if (CGF.getLangOpts().PointerOverflowDefined)
return CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
return CGF.EmitCheckedInBoundsGEP(
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index a0d6919c6dc8d0..3420472c0f75eb 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -575,6 +575,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
options::OPT_fstrict_overflow, false);
if (Args.hasFlagNoClaim(options::OPT_fwrapv, options::OPT_fno_wrapv, S))
Add &= ~SanitizerKind::SignedIntegerOverflow;
+ if (Args.hasFlagNoClaim(options::OPT_fwrapv_pointer,
+ options::OPT_fno_wrapv_pointer, S))
+ Add &= ~SanitizerKind::PointerOverflow;
}
Add &= Supported;
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index f8967890f722cf..8f5c38b38c2f8d 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -3106,12 +3106,19 @@ void tools::renderCommonIntegerOverflowOptions(const ArgList &Args,
ArgStringList &CmdArgs) {
// -fno-strict-overflow implies -fwrapv if it isn't disabled, but
// -fstrict-overflow won't turn off an explicitly enabled -fwrapv.
+ bool StrictOverflow = Args.hasFlag(options::OPT_fstrict_overflow,
+ options::OPT_fno_strict_overflow, true);
if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) {
if (A->getOption().matches(options::OPT_fwrapv))
CmdArgs.push_back("-fwrapv");
- } else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow,
- options::OPT_fno_strict_overflow)) {
- if (A->getOption().matches(options::OPT_fno_strict_overflow))
- CmdArgs.push_back("-fwrapv");
+ } else if (!StrictOverflow) {
+ CmdArgs.push_back("-fwrapv");
+ }
+ if (Arg *A = Args.getLastArg(options::OPT_fwrapv_pointer,
+ options::OPT_fno_wrapv_pointer)) {
+ if (A->getOption().matches(options::OPT_fwrapv_pointer))
+ CmdArgs.push_back("-fwrapv-pointer");
+ } else if (!StrictOverflow) {
+ CmdArgs.push_back("-fwrapv-pointer");
}
}
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 39bed84536c6a3..2acb4e49dba70b 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3721,6 +3721,8 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
} else if (Opts.SignedOverflowBehavior == LangOptions::SOB_Defined) {
GenerateArg(Consumer, OPT_fwrapv);
}
+ if (Opts.PointerOverflowDefined)
+ GenerateArg(Consumer, OPT_fwrapv_pointer);
if (Opts.MSCompatibilityVersion != 0) {
unsigned Major = Opts.MSCompatibilityVersion / 10000000;
@@ -4138,6 +4140,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
}
else if (Args.hasArg(OPT_fwrapv))
Opts.setSignedOverflowBehavior(LangOptions::SOB_Defined);
+ if (Args.hasArg(OPT_fwrapv_pointer))
+ Opts.PointerOverflowDefined = true;
Opts.MSCompatibilityVersion = 0;
if (const Arg *A = Args.getLastArg(OPT_fms_compatibility_version)) {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ae40895980d90a..4920688dff398e 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -11787,7 +11787,7 @@ static std::optional<bool> isTautologicalBoundsCheck(Sema &S, const Expr *LHS,
const Expr *RHS,
BinaryOperatorKind Opc) {
if (!LHS->getType()->isPointerType() ||
- S.getLangOpts().isSignedOverflowDefined())
+ S.getLangOpts().PointerOverflowDefined)
return std::nullopt;
// Canonicalize to >= or < predicate.
diff --git a/clang/test/CodeGen/integer-overflow.c b/clang/test/CodeGen/integer-overflow.c
index 9e8cde8b33b16e..9f1eca7e314c26 100644
--- a/clang/test/CodeGen/integer-overflow.c
+++ b/clang/test/CodeGen/integer-overflow.c
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s --check-prefix=DEFAULT
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fwrapv | FileCheck %s --check-prefix=WRAPV
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -ftrapv | FileCheck %s --check-prefix=TRAPV
-// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fsanitize=signed-integer-overflow | FileCheck %s --check-prefixes=CATCH_UB,CATCH_UB_POINTER
-// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fsanitize=signed-integer-overflow -fwrapv | FileCheck %s --check-prefixes=CATCH_UB,NOCATCH_UB_POINTER
+// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fsanitize=signed-integer-overflow | FileCheck %s --check-prefixes=CATCH_UB
+// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fsanitize=signed-integer-overflow -fwrapv | FileCheck %s --check-prefixes=CATCH_UB
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -ftrapv -ftrapv-handler foo | FileCheck %s --check-prefix=TRAPV_HANDLER
@@ -57,15 +57,6 @@ void test1(void) {
// TRAPV_HANDLER: foo(
--a;
- // -fwrapv should turn off inbounds for GEP's, PR9256
- extern int* P;
- ++P;
- // DEFAULT: getelementptr inbounds nuw i32, ptr
- // WRAPV: getelementptr i32, ptr
- // TRAPV: getelementptr inbounds nuw i32, ptr
- // CATCH_UB_POINTER: getelementptr inbounds nuw i32, ptr
- // NOCATCH_UB_POINTER: getelementptr i32, ptr
-
// PR9350: char pre-increment never overflows.
extern volatile signed char PR9350_char_inc;
// DEFAULT: add i8 {{.*}}, 1
diff --git a/clang/test/Driver/clang_wrapv_opts.c b/clang/test/Driver/clang_wrapv_opts.c
index 826468e0678d0b..c0045b95639b31 100644
--- a/clang/test/Driver/clang_wrapv_opts.c
+++ b/clang/test/Driver/clang_wrapv_opts.c
@@ -1,11 +1,24 @@
// RUN: %clang -### -S -fwrapv -fno-wrapv -fwrapv %s 2>&1 | FileCheck -check-prefix=CHECK1 %s
// CHECK1: -fwrapv
//
+// RUN: %clang -### -S -fwrapv-pointer -fno-wrapv-pointer -fwrapv-pointer %s 2>&1 | FileCheck -check-prefix=CHECK1-POINTER %s
+// CHECK1-POINTER: -fwrapv-pointer
+//
// RUN: %clang -### -S -fstrict-overflow -fno-strict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK2 %s
-// CHECK2: -fwrapv
+// CHECK2: -fwrapv{{.*}}-fwrapv-pointer
//
// RUN: %clang -### -S -fwrapv -fstrict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK3 %s
// CHECK3: -fwrapv
//
-// RUN: %clang -### -S -fno-wrapv -fno-strict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK4 %s
-// CHECK4-NOT: -fwrapv
+// RUN: %clang -### -S -fwrapv-pointer -fstrict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK3-POINTER %s
+// CHECK3-POINTER: -fwrapv-pointer
+//
+// RUN: %clang -### -S -fno-wrapv -fno-strict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK5 %s
+// CHECK5-NOT: -fwrapv
+// CHECK5: -fwrapv-pointer
+// CHECK5-NOT: -fwrapv
+//
+// RUN: %clang -### -S -fno-wrapv-pointer -fno-strict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK5-POINTER %s
+// CHECK5-POINTER-NOT: -fwrapv-pointer
+// CHECK5-POINTER: -fwrapv
+// CHECK5-POINTER-NOT: -fwrapv-pointer
diff --git a/clang/test/Sema/tautological-pointer-comparison.c b/clang/test/Sema/tautological-pointer-comparison.c
index 1c5973b01a30d0..f2a944b5305e4e 100644
--- a/clang/test/Sema/tautological-pointer-comparison.c
+++ b/clang/test/Sema/tautological-pointer-comparison.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -fwrapv -verify=fwrapv %s
+// RUN: %clang_cc1 -fsyntax-only -fwrapv-pointer -verify=fwrapv %s
// fwrapv-no-diagnostics
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
1f3737d
to
b32e3e1
Compare
I'm tempted to say we should just treat -fwrapv/-fwrapv-pointer/-fno-strict-overflow as aliases for each other. I don't think anyone using -fwrapv is going to be happy that we're turning on overflow optimizations. |
Yeah, I'm not entirely sure this change is worthwhile either. My general thinking here was that we already have the |
We (chromium) turned on fwrapv due to the pointer changes, and it had a bit of a perf hit. We'd probably switch to this, hoping it'd address the perf issues at least some. Matching gcc's behavior for -f flags both compilers have also makes sense, IMHO. |
GCC supports three flags related to overflow behavior: * `-fwrapv`: Makes signed integer overflow well-defined. * `-fwrapv-pointer`: Makes pointer overflow well-defined. * `-fno-strict-overflow`: Implies `-fwrapv -fwrapv-pointer`, making both signed integer overflow and pointer overflow well-defined. Clang currently only supports `-fno-strict-overflow` and `-fwrapv`, but not `-fwrapv-pointer`. This PR proposes to introduce `-fwrapv-pointer` and adjust the semantics of `-fwrapv` to match GCC. This allows signed integer overflow and pointer overflow to be controlled independently, while `-fno-strict-overflow` still exists to control both at the same time (and that option is consistent across GCC and Clang).
Agree with this, FWIW. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like matching gcc's behavior makes sense for users but I am not sure about the timing for clang-20. This seems like the change in behavior could be impactful.
If we want to make this change, I think doing it for Clang 20 would be ideal, because it is related to the pointer overflow optimization changes in that release. |
I am a bit concerned about the behavioral change, but given the more aggressive optimizations in LLVM 20, I think it makes sense to get this into Clang 20 to see what the fallout is during early RCs. If there's negative impact, we can consider cherry-picking a revert from the branch. Matching GCC's behavior for the options seems like a defensible approach. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes look correct to me, but I'd love to hear from the codegen and sanitizer experts as to whether they agree with the changes and the timeline to land it for 20.
to use ``-fwrapv-pointer`` to only make pointer overflow well-defined, while | ||
not affecting the behavior of signed integer overflow. | ||
|
||
- The ``-fwrapv`` flag now only makes signed integer overflow well-defined, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curiously enough, we only ever documented the signed integer overflow behavior, not the pointer overflow: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fwrapv
// -fwrapv should turn off inbounds for GEP's, PR9256 | ||
extern int* P; | ||
++P; | ||
// DEFAULT: getelementptr inbounds nuw i32, ptr | ||
// WRAPV: getelementptr i32, ptr | ||
// TRAPV: getelementptr inbounds nuw i32, ptr | ||
// CATCH_UB_POINTER: getelementptr inbounds nuw i32, ptr | ||
// NOCATCH_UB_POINTER: getelementptr i32, ptr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we keep the test but update the comment + expected results?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've restored the test. The intent here was to split off the pointer case into pointer-overflow.c, but there's no reason we can't have both...
clang/test/Driver/clang_wrapv_opts.c
Outdated
// | ||
// RUN: %clang -### -S -fwrapv -fstrict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK3 %s | ||
// CHECK3: -fwrapv | ||
// | ||
// RUN: %clang -### -S -fwrapv-pointer -fstrict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK3-POINTER %s | ||
// CHECK3-POINTER: -fwrapv-pointer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a NOT pattern for -fwrapv.
Perhaps use --implicit-check-not=-fwrap so that we don't need a NOT before and a NOT after the positive pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, I've switched the last four tests to use --implicit-check-not
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CC @llvm/clang-vendors : this changes the behavior of -fwrapv.
Internally, I expect it's going to be a bit painful to communicate to all our internal teams that they need to change their -fwrapv usage to -fno-strict-overflow, but if we think it's important to align with gcc in that respect, we can do it, I guess?
The implementation looks correct.
@@ -4311,14 +4311,14 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, | |||
// GEP indexes are signed, and scaling an index isn't permitted to | |||
// signed-overflow, so we use the same semantics for our explicit | |||
// multiply. We suppress this if overflow is not undefined behavior. | |||
if (getLangOpts().isSignedOverflowDefined()) { | |||
if (getLangOpts().PointerOverflowDefined) { | |||
Idx = Builder.CreateMul(Idx, numElements); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a gap in the pointer-overflow sanitizer: we should trigger the sanitizer if the multiply overflows. Same issue pops up in a few other places. But you don't need to fix this in this patch, I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opened #124358 .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will be used by chromium and other users. There is some gap in sanitizer that is not so important.
LGTM, but other reviewers need to stamp as well.
clang/test/Driver/clang_wrapv_opts.c
Outdated
// | ||
// RUN: %clang -### -S -fwrapv -fstrict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK3 %s | ||
// RUN: %clang -### -S -fwrapv -fstrict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK3 %s --implicit-check-not="-fwrapv-pointer" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When testing both -fno-strict-overflow and -fwrapv{-pointer}, perhaps add -Werror to ensure that we don't emit a unused option warning (which would happen if the Driver code forgot to claim an option).
clang/test/Driver/clang_wrapv_opts.c
Outdated
// CHECK4: -fwrapv-pointer | ||
// | ||
// RUN: %clang -### -S -fno-wrapv-pointer -fno-strict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK4-POINTER %s --implicit-check-not="-fwrapv-pointer" | ||
// CHECK4-POINTER: -fwrapv |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might need "-fwrapv"
. Otherwise, IIUC even if the output is -fwrap-pointer
, the check will pass. Because -fwrapv
matches, and the remaining string will pass the --implicit-check-not check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/73/builds/12566 Here is the relevant piece of the build log for the reference
|
In gcc, -fwrapv only controls signed integer overflow, and -fwrapv-pointer only controls pointer overflow. In our current clang, -fwrapv controls both, but in a new clang [1], clang is moving to match gcc. -fno-strict-overflow controls both signed integer and pointer overflow. Switch to that to get the same behavior for new clang (and current clang) that we currently have, and to also give gcc that behavior. No intentional behavior change in clang builds. With current clang, -fwrapv and -fno-strict-overflow should mean the same thing. Once we updated to new clang, we can consider using just -fwrapv-pointer. 1: llvm/llvm-project#122486 Bug: 336282133,384391188,389103111 Change-Id: I6ace8efb4e547ec84ce069c097dce464b15d63ea Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6207309 Auto-Submit: Nico Weber <[email protected]> Reviewed-by: Hans Wennborg <[email protected]> Commit-Queue: Nico Weber <[email protected]> Commit-Queue: Hans Wennborg <[email protected]> Cr-Commit-Position: refs/heads/main@{#1412288}
This reverts commit dc86334. Reason for revert: LUCI Bisection has identified this change as the culprit of a build failure. See the analysis: https://ci.chromium.org/ui/p/chromium/bisection/compile-analysis/b/8724486005851749873 Sample failed build: https://ci.chromium.org/b/8724486005851749873 If this is a false positive, please report it at http://b.corp.google.com/createIssue?component=1199205&description=Analysis%3A+https%3A%2F%2Fchromium-review.googlesource.com%2Fc%2Fchromium%2Fsrc%2F%2B%2F6207309&format=PLAIN&priority=P3&title=Wrongly+blamed+https%3A%2F%2Fci.chromium.org%2Fui%2Fp%2Fchromium%2Fbisection%2Fcompile-analysis%2Fb%2F8724486005851749873&type=BUG Original change's description: > build: Use -fno-strict-overflow instead of -fwrapv > > In gcc, -fwrapv only controls signed integer overflow, and > -fwrapv-pointer only controls pointer overflow. > > In our current clang, -fwrapv controls both, but in a new > clang [1], clang is moving to match gcc. > > -fno-strict-overflow controls both signed integer and > pointer overflow. Switch to that to get the same behavior for > new clang (and current clang) that we currently have, and to > also give gcc that behavior. > > No intentional behavior change in clang builds. With current > clang, -fwrapv and -fno-strict-overflow should mean the same > thing. > > Once we updated to new clang, we can consider using just > -fwrapv-pointer. > > 1: llvm/llvm-project#122486 > > Bug: 336282133,384391188,389103111 > Change-Id: I6ace8efb4e547ec84ce069c097dce464b15d63ea > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6207309 > Auto-Submit: Nico Weber <[email protected]> > Reviewed-by: Hans Wennborg <[email protected]> > Commit-Queue: Nico Weber <[email protected]> > Commit-Queue: Hans Wennborg <[email protected]> > Cr-Commit-Position: refs/heads/main@{#1412288} > Bug: 336282133,384391188,389103111 Change-Id: I6b6d87fd75059dd782f8a3a16c30a6668e354bb6 No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6208248 Bot-Commit: [email protected] <[email protected]> Owners-Override: [email protected] <[email protected]> Commit-Queue: [email protected] <[email protected]> Cr-Commit-Position: refs/heads/main@{#1412319}
…53-gba476d0b-1 / ad211ced81509462cdfe4c29ed10f97279a0acae-1 : d4bdd1ed551fed0c951eb47b4be2c79d7a02d181-1 Note: this increments the LLVM major version to 21. Also use -fno-strict-overflow instead of -fwrapv, since the latter no longer covers pointer overflow [1]. https://chromium.googlesource.com/external/github.com/llvm/llvm-project/+log/29ed6000..ba476d0b https://chromium.googlesource.com/external/github.com/rust-lang/rust/+log/ad211ced8150..d4bdd1ed551f Ran: ./tools/clang/scripts/upload_revision.py ba476d0b83dc8a4bbf066dc02a0f73ded27114f0 [1] llvm/llvm-project#122486 Binary-Size: Should be within the limits with new PGO profiles. Bug: 389103111 Change-Id: I1eb3c31628b58c2d71e3690b967ffad5609d673d Disable-Rts: True Cq-Include-Trybots: chromium/try:chromeos-amd64-generic-cfi-thin-lto-rel Cq-Include-Trybots: chromium/try:dawn-win10-x86-deps-rel Cq-Include-Trybots: chromium/try:linux-chromeos-dbg Cq-Include-Trybots: chromium/try:linux_chromium_cfi_rel_ng Cq-Include-Trybots: chromium/try:linux_chromium_chromeos_msan_rel_ng Cq-Include-Trybots: chromium/try:linux_chromium_msan_rel_ng Cq-Include-Trybots: chromium/try:mac11-arm64-rel,mac_chromium_asan_rel_ng Cq-Include-Trybots: chromium/try:ios-catalyst,win-asan,android-official Cq-Include-Trybots: chromium/try:fuchsia-arm64-cast-receiver-rel Cq-Include-Trybots: chromium/try:mac-official,linux-official Cq-Include-Trybots: chromium/try:win-official,win32-official Cq-Include-Trybots: chromium/try:win-arm64-rel Cq-Include-Trybots: chromium/try:linux-swangle-try-x64,win-swangle-try-x86 Cq-Include-Trybots: chromium/try:android-cronet-mainline-clang-arm64-dbg Cq-Include-Trybots: chromium/try:android-cronet-mainline-clang-arm64-rel Cq-Include-Trybots: chromium/try:android-cronet-mainline-clang-riscv64-dbg Cq-Include-Trybots: chromium/try:android-cronet-mainline-clang-riscv64-rel Cq-Include-Trybots: chromium/try:android-cronet-mainline-clang-x86-dbg Cq-Include-Trybots: chromium/try:android-cronet-mainline-clang-x86-rel Cq-Include-Trybots: chromium/try:android-cronet-riscv64-dbg Cq-Include-Trybots: chromium/try:android-cronet-riscv64-rel Cq-Include-Trybots: chrome/try:iphone-device,ipad-device Cq-Include-Trybots: chrome/try:linux-chromeos-chrome Cq-Include-Trybots: chrome/try:win-chrome,win64-chrome,linux-chrome,mac-chrome Cq-Include-Trybots: chrome/try:linux-pgo,mac-pgo,win32-pgo,win64-pgo Cq-Include-Trybots: luci.chromium.try:linux-cast-x64-rel Cq-Include-Trybots: chromium/try:android-rust-arm32-rel Cq-Include-Trybots: chromium/try:android-rust-arm64-dbg Cq-Include-Trybots: chromium/try:android-rust-arm64-rel Cq-Include-Trybots: chromium/try:linux-rust-x64-dbg Cq-Include-Trybots: chromium/try:linux-rust-x64-rel Cq-Include-Trybots: chromium/try:mac-rust-x64-dbg Cq-Include-Trybots: chromium/try:win-rust-x64-dbg Cq-Include-Trybots: chromium/try:win-rust-x64-rel Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6233983 Reviewed-by: Nico Weber <[email protected]> Auto-Submit: Hans Wennborg <[email protected]> Cr-Commit-Position: refs/heads/main@{#1417174}
In gcc, -fwrapv only controls signed integer overflow, and -fwrapv-pointer only controls pointer overflow. In our current clang, -fwrapv controls both, but in a new clang [1], clang is moving to match gcc. -fno-strict-overflow controls both signed integer and pointer overflow. Switch to that to get the same behavior for new clang (and current clang) that we currently have, and to also give gcc that behavior. No intentional behavior change in clang builds. With current clang, -fwrapv and -fno-strict-overflow should mean the same thing. Once we updated to new clang, we can consider using just -fwrapv-pointer. 1: llvm/llvm-project#122486 Bug: 336282133,384391188,389103111 Change-Id: I6ace8efb4e547ec84ce069c097dce464b15d63ea Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6207309 Auto-Submit: Nico Weber <[email protected]> Reviewed-by: Hans Wennborg <[email protected]> Commit-Queue: Nico Weber <[email protected]> Commit-Queue: Hans Wennborg <[email protected]> Cr-Commit-Position: refs/heads/main@{#1412288} NOKEYCHECK=True GitOrigin-RevId: dc86334c39e93197a89a9201475db12f4b42c9c9
This reverts commit dc86334c39e93197a89a9201475db12f4b42c9c9. Reason for revert: LUCI Bisection has identified this change as the culprit of a build failure. See the analysis: https://ci.chromium.org/ui/p/chromium/bisection/compile-analysis/b/8724486005851749873 Sample failed build: https://ci.chromium.org/b/8724486005851749873 If this is a false positive, please report it at http://b.corp.google.com/createIssue?component=1199205&description=Analysis%3A+https%3A%2F%2Fchromium-review.googlesource.com%2Fc%2Fchromium%2Fsrc%2F%2B%2F6207309&format=PLAIN&priority=P3&title=Wrongly+blamed+https%3A%2F%2Fci.chromium.org%2Fui%2Fp%2Fchromium%2Fbisection%2Fcompile-analysis%2Fb%2F8724486005851749873&type=BUG Original change's description: > build: Use -fno-strict-overflow instead of -fwrapv > > In gcc, -fwrapv only controls signed integer overflow, and > -fwrapv-pointer only controls pointer overflow. > > In our current clang, -fwrapv controls both, but in a new > clang [1], clang is moving to match gcc. > > -fno-strict-overflow controls both signed integer and > pointer overflow. Switch to that to get the same behavior for > new clang (and current clang) that we currently have, and to > also give gcc that behavior. > > No intentional behavior change in clang builds. With current > clang, -fwrapv and -fno-strict-overflow should mean the same > thing. > > Once we updated to new clang, we can consider using just > -fwrapv-pointer. > > 1: llvm/llvm-project#122486 > > Bug: 336282133,384391188,389103111 > Change-Id: I6ace8efb4e547ec84ce069c097dce464b15d63ea > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6207309 > Auto-Submit: Nico Weber <[email protected]> > Reviewed-by: Hans Wennborg <[email protected]> > Commit-Queue: Nico Weber <[email protected]> > Commit-Queue: Hans Wennborg <[email protected]> > Cr-Commit-Position: refs/heads/main@{#1412288} > Bug: 336282133,384391188,389103111 Change-Id: I6b6d87fd75059dd782f8a3a16c30a6668e354bb6 No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6208248 Bot-Commit: [email protected] <[email protected]> Owners-Override: [email protected] <[email protected]> Commit-Queue: [email protected] <[email protected]> Cr-Commit-Position: refs/heads/main@{#1412319} NOKEYCHECK=True GitOrigin-RevId: 86a302d2ce8c8ff36047f5700d7737fddb4e9c00
…53-gba476d0b-1 / ad211ced81509462cdfe4c29ed10f97279a0acae-1 : d4bdd1ed551fed0c951eb47b4be2c79d7a02d181-1 Note: this increments the LLVM major version to 21. Also use -fno-strict-overflow instead of -fwrapv, since the latter no longer covers pointer overflow [1]. https://chromium.googlesource.com/external/github.com/llvm/llvm-project/+log/29ed6000..ba476d0b https://chromium.googlesource.com/external/github.com/rust-lang/rust/+log/ad211ced8150..d4bdd1ed551f Ran: ./tools/clang/scripts/upload_revision.py ba476d0b83dc8a4bbf066dc02a0f73ded27114f0 [1] llvm/llvm-project#122486 Binary-Size: Should be within the limits with new PGO profiles. Bug: 389103111 Change-Id: I1eb3c31628b58c2d71e3690b967ffad5609d673d Disable-Rts: True Cq-Include-Trybots: chromium/try:chromeos-amd64-generic-cfi-thin-lto-rel Cq-Include-Trybots: chromium/try:dawn-win10-x86-deps-rel Cq-Include-Trybots: chromium/try:linux-chromeos-dbg Cq-Include-Trybots: chromium/try:linux_chromium_cfi_rel_ng Cq-Include-Trybots: chromium/try:linux_chromium_chromeos_msan_rel_ng Cq-Include-Trybots: chromium/try:linux_chromium_msan_rel_ng Cq-Include-Trybots: chromium/try:mac11-arm64-rel,mac_chromium_asan_rel_ng Cq-Include-Trybots: chromium/try:ios-catalyst,win-asan,android-official Cq-Include-Trybots: chromium/try:fuchsia-arm64-cast-receiver-rel Cq-Include-Trybots: chromium/try:mac-official,linux-official Cq-Include-Trybots: chromium/try:win-official,win32-official Cq-Include-Trybots: chromium/try:win-arm64-rel Cq-Include-Trybots: chromium/try:linux-swangle-try-x64,win-swangle-try-x86 Cq-Include-Trybots: chromium/try:android-cronet-mainline-clang-arm64-dbg Cq-Include-Trybots: chromium/try:android-cronet-mainline-clang-arm64-rel Cq-Include-Trybots: chromium/try:android-cronet-mainline-clang-riscv64-dbg Cq-Include-Trybots: chromium/try:android-cronet-mainline-clang-riscv64-rel Cq-Include-Trybots: chromium/try:android-cronet-mainline-clang-x86-dbg Cq-Include-Trybots: chromium/try:android-cronet-mainline-clang-x86-rel Cq-Include-Trybots: chromium/try:android-cronet-riscv64-dbg Cq-Include-Trybots: chromium/try:android-cronet-riscv64-rel Cq-Include-Trybots: chrome/try:iphone-device,ipad-device Cq-Include-Trybots: chrome/try:linux-chromeos-chrome Cq-Include-Trybots: chrome/try:win-chrome,win64-chrome,linux-chrome,mac-chrome Cq-Include-Trybots: chrome/try:linux-pgo,mac-pgo,win32-pgo,win64-pgo Cq-Include-Trybots: luci.chromium.try:linux-cast-x64-rel Cq-Include-Trybots: chromium/try:android-rust-arm32-rel Cq-Include-Trybots: chromium/try:android-rust-arm64-dbg Cq-Include-Trybots: chromium/try:android-rust-arm64-rel Cq-Include-Trybots: chromium/try:linux-rust-x64-dbg Cq-Include-Trybots: chromium/try:linux-rust-x64-rel Cq-Include-Trybots: chromium/try:mac-rust-x64-dbg Cq-Include-Trybots: chromium/try:win-rust-x64-dbg Cq-Include-Trybots: chromium/try:win-rust-x64-rel Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6233983 Reviewed-by: Nico Weber <[email protected]> Auto-Submit: Hans Wennborg <[email protected]> Cr-Commit-Position: refs/heads/main@{#1417174} NOKEYCHECK=True GitOrigin-RevId: 7c222671e7164bd6b726ef1d8d6e73403ad72559
GCC supports three flags related to overflow behavior:
-fwrapv
: Makes signed integer overflow well-defined.-fwrapv-pointer
: Makes pointer overflow well-defined.-fno-strict-overflow
: Implies-fwrapv -fwrapv-pointer
, making both signed integer overflow and pointer overflow well-defined.Clang currently only supports
-fno-strict-overflow
and-fwrapv
, but not-fwrapv-pointer
.This PR proposes to introduce
-fwrapv-pointer
and adjust the semantics of-fwrapv
to match GCC.This allows signed integer overflow and pointer overflow to be controlled independently, while
-fno-strict-overflow
still exists to control both at the same time (and that option is consistent across GCC and Clang).