forked from OSchip/llvm-project
Treat the range of representable values of floating-point types as [-inf, +inf] not as [-max, +max].
Summary: Prior to r329065, we used [-max, max] as the range of representable values because LLVM's `fptrunc` did not guarantee defined behavior when truncating from a larger floating-point type to a smaller one. Now that has been fixed, we can make clang follow normal IEEE 754 semantics in this regard and take the larger range [-inf, +inf] as the range of representable values. In practice, this affects two parts of the frontend: * the constant evaluator no longer treats floating-point evaluations that result in +-inf as being undefined (because they no longer leave the range of representable values of the type) * UBSan no longer treats conversions to floating-point type that are outside the [-max, +max] range as being undefined In passing, also remove the float-divide-by-zero sanitizer from -fsanitize=undefined, on the basis that while it's undefined per C++ rules (and we disallow it in constant expressions for that reason), it is defined by Clang / LLVM / IEEE 754. Reviewers: rnk, BillyONeal Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D63793 llvm-svn: 365272
This commit is contained in:
parent
a7145c45a7
commit
9e52c43090
|
@ -83,9 +83,13 @@ Available checks are:
|
|||
type.
|
||||
- ``-fsanitize=float-cast-overflow``: Conversion to, from, or
|
||||
between floating-point types which would overflow the
|
||||
destination.
|
||||
destination. Because the range of representable values for all
|
||||
floating-point types supported by Clang is [-inf, +inf], the only
|
||||
cases detected are conversions from floating point to integer types.
|
||||
- ``-fsanitize=float-divide-by-zero``: Floating point division by
|
||||
zero.
|
||||
zero. This is undefined per the C and C++ standards, but is defined
|
||||
by Clang (and by ISO/IEC/IEEE 60559 / IEEE 754) as producing either an
|
||||
infinity or NaN value, so is not included in ``-fsanitize=undefined``.
|
||||
- ``-fsanitize=function``: Indirect call of a function through a
|
||||
function pointer of the wrong type (Darwin/Linux, C++ and x86/x86_64
|
||||
only).
|
||||
|
@ -163,8 +167,8 @@ Available checks are:
|
|||
|
||||
You can also use the following check groups:
|
||||
- ``-fsanitize=undefined``: All of the checks listed above other than
|
||||
``unsigned-integer-overflow``, ``implicit-conversion`` and the
|
||||
``nullability-*`` group of checks.
|
||||
``float-divide-by-zero``, ``unsigned-integer-overflow``,
|
||||
``implicit-conversion``, and the ``nullability-*`` group of checks.
|
||||
- ``-fsanitize=undefined-trap``: Deprecated alias of
|
||||
``-fsanitize=undefined``.
|
||||
- ``-fsanitize=implicit-integer-truncation``: Catches lossy integral
|
||||
|
@ -174,16 +178,16 @@ You can also use the following check groups:
|
|||
conversions that change the arithmetic value of the integer. Enables
|
||||
``implicit-signed-integer-truncation`` and ``implicit-integer-sign-change``.
|
||||
- ``-fsanitize=implicit-conversion``: Checks for suspicious
|
||||
behaviour of implicit conversions. Enables
|
||||
behavior of implicit conversions. Enables
|
||||
``implicit-unsigned-integer-truncation``,
|
||||
``implicit-signed-integer-truncation`` and
|
||||
``implicit-signed-integer-truncation``, and
|
||||
``implicit-integer-sign-change``.
|
||||
- ``-fsanitize=integer``: Checks for undefined or suspicious integer
|
||||
behavior (e.g. unsigned integer overflow).
|
||||
Enables ``signed-integer-overflow``, ``unsigned-integer-overflow``,
|
||||
``shift``, ``integer-divide-by-zero``,
|
||||
``implicit-unsigned-integer-truncation``,
|
||||
``implicit-signed-integer-truncation`` and
|
||||
``implicit-signed-integer-truncation``, and
|
||||
``implicit-integer-sign-change``.
|
||||
- ``-fsanitize=nullability``: Enables ``nullability-arg``,
|
||||
``nullability-assign``, and ``nullability-return``. While violating
|
||||
|
|
|
@ -130,7 +130,7 @@ SANITIZER("shadow-call-stack", ShadowCallStack)
|
|||
// ABI or address space layout implications, and only catch undefined behavior.
|
||||
SANITIZER_GROUP("undefined", Undefined,
|
||||
Alignment | Bool | Builtin | ArrayBounds | Enum |
|
||||
FloatCastOverflow | FloatDivideByZero |
|
||||
FloatCastOverflow |
|
||||
IntegerDivideByZero | NonnullAttribute | Null | ObjectSize |
|
||||
PointerOverflow | Return | ReturnsNonnullAttribute | Shift |
|
||||
SignedIntegerOverflow | Unreachable | VLABound | Function |
|
||||
|
|
|
@ -2212,10 +2212,8 @@ static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E,
|
|||
APFloat &Result) {
|
||||
APFloat Value = Result;
|
||||
bool ignored;
|
||||
if (Result.convert(Info.Ctx.getFloatTypeSemantics(DestType),
|
||||
APFloat::rmNearestTiesToEven, &ignored)
|
||||
& APFloat::opOverflow)
|
||||
return HandleOverflow(Info, E, Value, DestType);
|
||||
Result.convert(Info.Ctx.getFloatTypeSemantics(DestType),
|
||||
APFloat::rmNearestTiesToEven, &ignored);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2236,10 +2234,8 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
|
|||
QualType SrcType, const APSInt &Value,
|
||||
QualType DestType, APFloat &Result) {
|
||||
Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1);
|
||||
if (Result.convertFromAPInt(Value, Value.isSigned(),
|
||||
APFloat::rmNearestTiesToEven)
|
||||
& APFloat::opOverflow)
|
||||
return HandleOverflow(Info, E, Value, DestType);
|
||||
Result.convertFromAPInt(Value, Value.isSigned(),
|
||||
APFloat::rmNearestTiesToEven);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2457,11 +2453,19 @@ static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E,
|
|||
LHS.subtract(RHS, APFloat::rmNearestTiesToEven);
|
||||
break;
|
||||
case BO_Div:
|
||||
// [expr.mul]p4:
|
||||
// If the second operand of / or % is zero the behavior is undefined.
|
||||
if (RHS.isZero())
|
||||
Info.CCEDiag(E, diag::note_expr_divide_by_zero);
|
||||
LHS.divide(RHS, APFloat::rmNearestTiesToEven);
|
||||
break;
|
||||
}
|
||||
|
||||
if (LHS.isInfinity() || LHS.isNaN()) {
|
||||
// [expr.pre]p4:
|
||||
// If during the evaluation of an expression, the result is not
|
||||
// mathematically defined [...], the behavior is undefined.
|
||||
// FIXME: C++ rules require us to not conform to IEEE 754 here.
|
||||
if (LHS.isNaN()) {
|
||||
Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN();
|
||||
return Info.noteUndefinedBehavior();
|
||||
}
|
||||
|
|
|
@ -313,7 +313,7 @@ public:
|
|||
/// boolean (i1) truth value. This is equivalent to "Val != 0".
|
||||
Value *EmitConversionToBool(Value *Src, QualType DstTy);
|
||||
|
||||
/// Emit a check that a conversion to or from a floating-point type does not
|
||||
/// Emit a check that a conversion from a floating-point type does not
|
||||
/// overflow.
|
||||
void EmitFloatConversionCheck(Value *OrigSrc, QualType OrigSrcType,
|
||||
Value *Src, QualType SrcType, QualType DstType,
|
||||
|
@ -864,129 +864,64 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) {
|
|||
void ScalarExprEmitter::EmitFloatConversionCheck(
|
||||
Value *OrigSrc, QualType OrigSrcType, Value *Src, QualType SrcType,
|
||||
QualType DstType, llvm::Type *DstTy, SourceLocation Loc) {
|
||||
assert(SrcType->isFloatingType() && "not a conversion from floating point");
|
||||
if (!isa<llvm::IntegerType>(DstTy))
|
||||
return;
|
||||
|
||||
CodeGenFunction::SanitizerScope SanScope(&CGF);
|
||||
using llvm::APFloat;
|
||||
using llvm::APSInt;
|
||||
|
||||
llvm::Type *SrcTy = Src->getType();
|
||||
|
||||
llvm::Value *Check = nullptr;
|
||||
if (llvm::IntegerType *IntTy = dyn_cast<llvm::IntegerType>(SrcTy)) {
|
||||
// Integer to floating-point. This can fail for unsigned short -> __half
|
||||
// or unsigned __int128 -> float.
|
||||
assert(DstType->isFloatingType());
|
||||
bool SrcIsUnsigned = OrigSrcType->isUnsignedIntegerOrEnumerationType();
|
||||
const llvm::fltSemantics &SrcSema =
|
||||
CGF.getContext().getFloatTypeSemantics(OrigSrcType);
|
||||
|
||||
APFloat LargestFloat =
|
||||
APFloat::getLargest(CGF.getContext().getFloatTypeSemantics(DstType));
|
||||
APSInt LargestInt(IntTy->getBitWidth(), SrcIsUnsigned);
|
||||
// Floating-point to integer. This has undefined behavior if the source is
|
||||
// +-Inf, NaN, or doesn't fit into the destination type (after truncation
|
||||
// to an integer).
|
||||
unsigned Width = CGF.getContext().getIntWidth(DstType);
|
||||
bool Unsigned = DstType->isUnsignedIntegerOrEnumerationType();
|
||||
|
||||
bool IsExact;
|
||||
if (LargestFloat.convertToInteger(LargestInt, APFloat::rmTowardZero,
|
||||
&IsExact) != APFloat::opOK)
|
||||
// The range of representable values of this floating point type includes
|
||||
// all values of this integer type. Don't need an overflow check.
|
||||
return;
|
||||
APSInt Min = APSInt::getMinValue(Width, Unsigned);
|
||||
APFloat MinSrc(SrcSema, APFloat::uninitialized);
|
||||
if (MinSrc.convertFromAPInt(Min, !Unsigned, APFloat::rmTowardZero) &
|
||||
APFloat::opOverflow)
|
||||
// Don't need an overflow check for lower bound. Just check for
|
||||
// -Inf/NaN.
|
||||
MinSrc = APFloat::getInf(SrcSema, true);
|
||||
else
|
||||
// Find the largest value which is too small to represent (before
|
||||
// truncation toward zero).
|
||||
MinSrc.subtract(APFloat(SrcSema, 1), APFloat::rmTowardNegative);
|
||||
|
||||
llvm::Value *Max = llvm::ConstantInt::get(VMContext, LargestInt);
|
||||
if (SrcIsUnsigned)
|
||||
Check = Builder.CreateICmpULE(Src, Max);
|
||||
else {
|
||||
llvm::Value *Min = llvm::ConstantInt::get(VMContext, -LargestInt);
|
||||
llvm::Value *GE = Builder.CreateICmpSGE(Src, Min);
|
||||
llvm::Value *LE = Builder.CreateICmpSLE(Src, Max);
|
||||
Check = Builder.CreateAnd(GE, LE);
|
||||
}
|
||||
} else {
|
||||
const llvm::fltSemantics &SrcSema =
|
||||
CGF.getContext().getFloatTypeSemantics(OrigSrcType);
|
||||
if (isa<llvm::IntegerType>(DstTy)) {
|
||||
// Floating-point to integer. This has undefined behavior if the source is
|
||||
// +-Inf, NaN, or doesn't fit into the destination type (after truncation
|
||||
// to an integer).
|
||||
unsigned Width = CGF.getContext().getIntWidth(DstType);
|
||||
bool Unsigned = DstType->isUnsignedIntegerOrEnumerationType();
|
||||
APSInt Max = APSInt::getMaxValue(Width, Unsigned);
|
||||
APFloat MaxSrc(SrcSema, APFloat::uninitialized);
|
||||
if (MaxSrc.convertFromAPInt(Max, !Unsigned, APFloat::rmTowardZero) &
|
||||
APFloat::opOverflow)
|
||||
// Don't need an overflow check for upper bound. Just check for
|
||||
// +Inf/NaN.
|
||||
MaxSrc = APFloat::getInf(SrcSema, false);
|
||||
else
|
||||
// Find the smallest value which is too large to represent (before
|
||||
// truncation toward zero).
|
||||
MaxSrc.add(APFloat(SrcSema, 1), APFloat::rmTowardPositive);
|
||||
|
||||
APSInt Min = APSInt::getMinValue(Width, Unsigned);
|
||||
APFloat MinSrc(SrcSema, APFloat::uninitialized);
|
||||
if (MinSrc.convertFromAPInt(Min, !Unsigned, APFloat::rmTowardZero) &
|
||||
APFloat::opOverflow)
|
||||
// Don't need an overflow check for lower bound. Just check for
|
||||
// -Inf/NaN.
|
||||
MinSrc = APFloat::getInf(SrcSema, true);
|
||||
else
|
||||
// Find the largest value which is too small to represent (before
|
||||
// truncation toward zero).
|
||||
MinSrc.subtract(APFloat(SrcSema, 1), APFloat::rmTowardNegative);
|
||||
|
||||
APSInt Max = APSInt::getMaxValue(Width, Unsigned);
|
||||
APFloat MaxSrc(SrcSema, APFloat::uninitialized);
|
||||
if (MaxSrc.convertFromAPInt(Max, !Unsigned, APFloat::rmTowardZero) &
|
||||
APFloat::opOverflow)
|
||||
// Don't need an overflow check for upper bound. Just check for
|
||||
// +Inf/NaN.
|
||||
MaxSrc = APFloat::getInf(SrcSema, false);
|
||||
else
|
||||
// Find the smallest value which is too large to represent (before
|
||||
// truncation toward zero).
|
||||
MaxSrc.add(APFloat(SrcSema, 1), APFloat::rmTowardPositive);
|
||||
|
||||
// If we're converting from __half, convert the range to float to match
|
||||
// the type of src.
|
||||
if (OrigSrcType->isHalfType()) {
|
||||
const llvm::fltSemantics &Sema =
|
||||
CGF.getContext().getFloatTypeSemantics(SrcType);
|
||||
bool IsInexact;
|
||||
MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
|
||||
MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
|
||||
}
|
||||
|
||||
llvm::Value *GE =
|
||||
Builder.CreateFCmpOGT(Src, llvm::ConstantFP::get(VMContext, MinSrc));
|
||||
llvm::Value *LE =
|
||||
Builder.CreateFCmpOLT(Src, llvm::ConstantFP::get(VMContext, MaxSrc));
|
||||
Check = Builder.CreateAnd(GE, LE);
|
||||
} else {
|
||||
// FIXME: Maybe split this sanitizer out from float-cast-overflow.
|
||||
//
|
||||
// Floating-point to floating-point. This has undefined behavior if the
|
||||
// source is not in the range of representable values of the destination
|
||||
// type. The C and C++ standards are spectacularly unclear here. We
|
||||
// diagnose finite out-of-range conversions, but allow infinities and NaNs
|
||||
// to convert to the corresponding value in the smaller type.
|
||||
//
|
||||
// C11 Annex F gives all such conversions defined behavior for IEC 60559
|
||||
// conforming implementations. Unfortunately, LLVM's fptrunc instruction
|
||||
// does not.
|
||||
|
||||
// Converting from a lower rank to a higher rank can never have
|
||||
// undefined behavior, since higher-rank types must have a superset
|
||||
// of values of lower-rank types.
|
||||
if (CGF.getContext().getFloatingTypeOrder(OrigSrcType, DstType) != 1)
|
||||
return;
|
||||
|
||||
assert(!OrigSrcType->isHalfType() &&
|
||||
"should not check conversion from __half, it has the lowest rank");
|
||||
|
||||
const llvm::fltSemantics &DstSema =
|
||||
CGF.getContext().getFloatTypeSemantics(DstType);
|
||||
APFloat MinBad = APFloat::getLargest(DstSema, false);
|
||||
APFloat MaxBad = APFloat::getInf(DstSema, false);
|
||||
|
||||
bool IsInexact;
|
||||
MinBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact);
|
||||
MaxBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact);
|
||||
|
||||
Value *AbsSrc = CGF.EmitNounwindRuntimeCall(
|
||||
CGF.CGM.getIntrinsic(llvm::Intrinsic::fabs, Src->getType()), Src);
|
||||
llvm::Value *GE =
|
||||
Builder.CreateFCmpOGT(AbsSrc, llvm::ConstantFP::get(VMContext, MinBad));
|
||||
llvm::Value *LE =
|
||||
Builder.CreateFCmpOLT(AbsSrc, llvm::ConstantFP::get(VMContext, MaxBad));
|
||||
Check = Builder.CreateNot(Builder.CreateAnd(GE, LE));
|
||||
}
|
||||
// If we're converting from __half, convert the range to float to match
|
||||
// the type of src.
|
||||
if (OrigSrcType->isHalfType()) {
|
||||
const llvm::fltSemantics &Sema =
|
||||
CGF.getContext().getFloatTypeSemantics(SrcType);
|
||||
bool IsInexact;
|
||||
MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
|
||||
MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
|
||||
}
|
||||
|
||||
llvm::Value *GE =
|
||||
Builder.CreateFCmpOGT(Src, llvm::ConstantFP::get(VMContext, MinSrc));
|
||||
llvm::Value *LE =
|
||||
Builder.CreateFCmpOLT(Src, llvm::ConstantFP::get(VMContext, MaxSrc));
|
||||
Check = Builder.CreateAnd(GE, LE);
|
||||
|
||||
llvm::Constant *StaticArgs[] = {CGF.EmitCheckSourceLocation(Loc),
|
||||
CGF.EmitCheckTypeDescriptor(OrigSrcType),
|
||||
CGF.EmitCheckTypeDescriptor(DstType)};
|
||||
|
@ -1391,9 +1326,12 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
|
|||
llvm::Type *ResTy = DstTy;
|
||||
|
||||
// An overflowing conversion has undefined behavior if either the source type
|
||||
// or the destination type is a floating-point type.
|
||||
// or the destination type is a floating-point type. However, we consider the
|
||||
// range of representable values for all floating-point types to be
|
||||
// [-inf,+inf], so no overflow can ever happen when the destination type is a
|
||||
// floating-point type.
|
||||
if (CGF.SanOpts.has(SanitizerKind::FloatCastOverflow) &&
|
||||
(OrigSrcType->isFloatingType() || DstType->isFloatingType()))
|
||||
OrigSrcType->isFloatingType())
|
||||
EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType, DstTy,
|
||||
Loc);
|
||||
|
||||
|
|
|
@ -136,9 +136,9 @@ namespace UndefinedBehavior {
|
|||
case (int)10000000000ll: // expected-note {{here}}
|
||||
case (unsigned int)10000000000ll: // expected-error {{duplicate case value}}
|
||||
case (int)(unsigned)(long long)4.4e9: // ok
|
||||
case (int)(float)1e300: // expected-error {{constant expression}} expected-note {{value 1.0E+300 is outside the range of representable values of type 'float'}}
|
||||
case (int)(float)1e300: // expected-error {{constant expression}} expected-note {{value +Inf is outside the range of representable values of type 'int'}}
|
||||
case (int)((float)1e37 / 1e30): // ok
|
||||
case (int)(__fp16)65536: // expected-error {{constant expression}} expected-note {{value 65536 is outside the range of representable values of type '__fp16'}}
|
||||
case (int)(__fp16)65536: // expected-error {{constant expression}} expected-note {{value +Inf is outside the range of representable values of type 'int'}}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -264,14 +264,28 @@ namespace UndefinedBehavior {
|
|||
static_assert(0u - 1u == 4294967295u, ""); // ok
|
||||
static_assert(~0u * ~0u == 1u, ""); // ok
|
||||
|
||||
template<typename T> constexpr bool isinf(T v) { return v && v / 2 == v; }
|
||||
|
||||
// Floating-point overflow and NaN.
|
||||
constexpr float f1 = 1e38f * 3.4028f; // ok
|
||||
constexpr float f2 = 1e38f * 3.4029f; // expected-error {{constant expression}} expected-note {{floating point arithmetic produces an infinity}}
|
||||
constexpr float f2 = 1e38f * 3.4029f; // ok, +inf is in range of representable values
|
||||
constexpr float f3 = 1e38f / -.2939f; // ok
|
||||
constexpr float f4 = 1e38f / -.2938f; // expected-error {{constant expression}} expected-note {{floating point arithmetic produces an infinity}}
|
||||
constexpr float f5 = 2e38f + 2e38f; // expected-error {{constant expression}} expected-note {{floating point arithmetic produces an infinity}}
|
||||
constexpr float f6 = -2e38f - 2e38f; // expected-error {{constant expression}} expected-note {{floating point arithmetic produces an infinity}}
|
||||
constexpr float f7 = 0.f / 0.f; // expected-error {{constant expression}} expected-note {{floating point arithmetic produces a NaN}}
|
||||
constexpr float f4 = 1e38f / -.2938f; // ok, -inf is in range of representable values
|
||||
constexpr float f5 = 2e38f + 2e38f; // ok, +inf is in range of representable values
|
||||
constexpr float f6 = -2e38f - 2e38f; // ok, -inf is in range of representable values
|
||||
constexpr float f7 = 0.f / 0.f; // expected-error {{constant expression}} expected-note {{division by zero}}
|
||||
constexpr float f8 = 1.f / 0.f; // expected-error {{constant expression}} expected-note {{division by zero}}
|
||||
constexpr float f9 = 1e308 / 1e-308; // ok, +inf
|
||||
constexpr float f10 = f2 - f2; // expected-error {{constant expression}} expected-note {{produces a NaN}}
|
||||
constexpr float f11 = f2 + f4; // expected-error {{constant expression}} expected-note {{produces a NaN}}
|
||||
constexpr float f12 = f2 / f2; // expected-error {{constant expression}} expected-note {{produces a NaN}}
|
||||
static_assert(!isinf(f1), "");
|
||||
static_assert(isinf(f2), "");
|
||||
static_assert(!isinf(f3), "");
|
||||
static_assert(isinf(f4), "");
|
||||
static_assert(isinf(f5), "");
|
||||
static_assert(isinf(f6), "");
|
||||
static_assert(isinf(f9), "");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
// CHECK-UBSAN: @[[LINE_700:.*]] = {{.*}}, i32 700, i32 14 {{.*}} @[[STRUCT_S]], i8 2, i8 3 }
|
||||
// CHECK-UBSAN: @[[LINE_800:.*]] = {{.*}}, i32 800, i32 12 {{.*}} @{{.*}} }
|
||||
// CHECK-UBSAN: @[[LINE_900:.*]] = {{.*}}, i32 900, i32 11 {{.*}} @{{.*}} }
|
||||
// CHECK-UBSAN: @[[LINE_1000:.*]] = {{.*}}, i32 1000, i32 10 {{.*}} @{{.*}} }
|
||||
// CHECK-UBSAN: @[[FP16:.*]] = private unnamed_addr constant { i16, i16, [9 x i8] } { i16 1, i16 16, [9 x i8] c"'__fp16'\00" }
|
||||
// CHECK-UBSAN: @[[LINE_1100:.*]] = {{.*}}, i32 1100, i32 8 {{.*}} @{{.*}} }
|
||||
// CHECK-UBSAN: @[[LINE_1200:.*]] = {{.*}}, i32 1200, i32 10 {{.*}} @{{.*}} }
|
||||
// CHECK-UBSAN: @[[LINE_1300:.*]] = {{.*}}, i32 1300, i32 10 {{.*}} @{{.*}} }
|
||||
// CHECK-UBSAN: @[[LINE_1400:.*]] = {{.*}}, i32 1400, i32 10 {{.*}} @{{.*}} }
|
||||
|
@ -27,7 +25,6 @@
|
|||
// CHECK-UBSAN: @[[LINE_1500:.*]] = {{.*}}, i32 1500, i32 10 {{.*}} @[[FP16]], {{.*}} }
|
||||
// CHECK-UBSAN: @[[SCHAR:.*]] = private unnamed_addr constant { i16, i16, [14 x i8] } { i16 0, i16 7, [14 x i8] c"'signed char'\00" }
|
||||
// CHECK-UBSAN: @[[LINE_1500:.*]] = {{.*}}, i32 1500, i32 10 {{.*}} @[[FP16]], {{.*}} }
|
||||
// CHECK-UBSAN: @[[LINE_1600:.*]] = {{.*}}, i32 1600, i32 10 {{.*}} @{{.*}} }
|
||||
|
||||
// PR6805
|
||||
// CHECK-COMMON-LABEL: @foo
|
||||
|
@ -197,30 +194,16 @@ float int_float_no_overflow(__int128 n) {
|
|||
|
||||
// CHECK-COMMON-LABEL: @int_float_overflow
|
||||
float int_float_overflow(unsigned __int128 n) {
|
||||
// This is 2**104. FLT_MAX is 2**128 - 2**104.
|
||||
// CHECK-COMMON: %[[INBOUNDS:.*]] = icmp ule i128 %{{.*}}, -20282409603651670423947251286016
|
||||
// CHECK-COMMON-NEXT: br i1 %[[INBOUNDS]]
|
||||
|
||||
// CHECK-UBSAN: call void @__ubsan_handle_float_cast_overflow(i8* bitcast ({{.*}} @[[LINE_1000]] to i8*),
|
||||
|
||||
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
|
||||
// CHECK-TRAP-NEXT: unreachable
|
||||
#line 1000
|
||||
// CHECK-UBSAN-NOT: call {{.*}} @__ubsan_handle_float_cast_overflow(
|
||||
// CHECK-TRAP-NOT: call {{.*}} @llvm.trap(
|
||||
// CHECK-COMMON: }
|
||||
return n;
|
||||
}
|
||||
|
||||
// CHECK-COMMON-LABEL: @int_fp16_overflow
|
||||
void int_fp16_overflow(int n, __fp16 *p) {
|
||||
// CHECK-COMMON: %[[GE:.*]] = icmp sge i32 %{{.*}}, -65504
|
||||
// CHECK-COMMON: %[[LE:.*]] = icmp sle i32 %{{.*}}, 65504
|
||||
// CHECK-COMMON: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
|
||||
// CHECK-COMMON-NEXT: br i1 %[[INBOUNDS]]
|
||||
|
||||
// CHECK-UBSAN: call void @__ubsan_handle_float_cast_overflow(i8* bitcast ({{.*}} @[[LINE_1100]] to i8*),
|
||||
|
||||
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
|
||||
// CHECK-TRAP-NEXT: unreachable
|
||||
#line 1100
|
||||
// CHECK-UBSAN-NOT: call {{.*}} @__ubsan_handle_float_cast_overflow(
|
||||
// CHECK-COMMON: }
|
||||
*p = n;
|
||||
}
|
||||
|
||||
|
@ -292,18 +275,9 @@ signed char fp16_char_overflow(__fp16 *p) {
|
|||
|
||||
// CHECK-COMMON-LABEL: @float_float_overflow
|
||||
float float_float_overflow(double f) {
|
||||
// CHECK-COMMON: %[[F:.*]] = call double @llvm.fabs.f64(
|
||||
// CHECK-COMMON: %[[GE:.*]] = fcmp ogt double %[[F]], 0x47EFFFFFE0000000
|
||||
// CHECK-COMMON: %[[LE:.*]] = fcmp olt double %[[F]], 0x7FF0000000000000
|
||||
// CHECK-COMMON: %[[OUTOFBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
|
||||
// CHECK-COMMON: %[[INBOUNDS:.*]] = xor i1 %[[OUTOFBOUNDS]], true
|
||||
// CHECK-COMMON-NEXT: br i1 %[[INBOUNDS]]
|
||||
|
||||
// CHECK-UBSAN: call void @__ubsan_handle_float_cast_overflow(i8* bitcast ({{.*}} @[[LINE_1600]] to i8*),
|
||||
|
||||
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
|
||||
// CHECK-TRAP-NEXT: unreachable
|
||||
#line 1600
|
||||
// CHECK-UBSAN-NOT: call {{.*}} @__ubsan_handle_float_cast_overflow(i8* bitcast ({{.*}} @[[LINE_1600]] to i8*),
|
||||
// CHECK-TRAP-NOT: call {{.*}} @llvm.trap() [[NR_NUW]]
|
||||
// CHECK-COMMON: }
|
||||
return f;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,15 +4,15 @@
|
|||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize-undefined-trap-on-error -fsanitize=undefined-trap %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP
|
||||
// CHECK-UNDEFINED-TRAP-NOT: -fsanitize-recover
|
||||
// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){19}"}}
|
||||
// CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
|
||||
// CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"
|
||||
// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}}
|
||||
// CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
|
||||
// CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"
|
||||
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
|
||||
// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){20}"}}
|
||||
// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){19}"}}
|
||||
|
||||
// RUN: %clang -target x86_64-apple-darwin10 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-DARWIN
|
||||
// CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){19}"}}
|
||||
// CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){18}"}}
|
||||
|
||||
// RUN: %clang -target i386-pc-win32 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN32
|
||||
// RUN: %clang -target i386-pc-win32 -fsanitize=undefined -x c++ %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN32 --check-prefix=CHECK-UNDEFINED-WIN-CXX
|
||||
|
@ -23,7 +23,7 @@
|
|||
// CHECK-UNDEFINED-WIN64: "--dependent-lib={{[^"]*}}ubsan_standalone-x86_64.lib"
|
||||
// CHECK-UNDEFINED-WIN64-MINGW: "--dependent-lib={{[^"]*}}libclang_rt.ubsan_standalone-x86_64.a"
|
||||
// CHECK-UNDEFINED-WIN-CXX: "--dependent-lib={{[^"]*}}ubsan_standalone_cxx{{[^"]*}}.lib"
|
||||
// CHECK-UNDEFINED-WIN-SAME: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){18}"}}
|
||||
// CHECK-UNDEFINED-WIN-SAME: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){17}"}}
|
||||
|
||||
// RUN: %clang -target i386-pc-win32 -fsanitize-coverage=bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-COVERAGE-WIN32
|
||||
// CHECK-COVERAGE-WIN32: "--dependent-lib={{[^"]*}}ubsan_standalone-i386.lib"
|
||||
|
@ -88,7 +88,7 @@
|
|||
// CHECK-FNO-SANITIZE-ALL: "-fsanitize=thread"
|
||||
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread,undefined -fno-sanitize=thread -fno-sanitize=float-cast-overflow,vptr,bool,builtin,enum %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-UNDEFINED
|
||||
// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|array-bounds|returns-nonnull-attribute|nonnull-attribute),?){15}"}}
|
||||
// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|array-bounds|returns-nonnull-attribute|nonnull-attribute),?){14}"}}
|
||||
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=shift -fno-sanitize=shift-base %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSANITIZE-SHIFT-PARTIAL
|
||||
// CHECK-FSANITIZE-SHIFT-PARTIAL: "-fsanitize=shift-exponent"
|
||||
|
@ -339,7 +339,7 @@
|
|||
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER-UBSAN
|
||||
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=all -fsanitize-recover=thread -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER-UBSAN
|
||||
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover=all -fno-sanitize-recover=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER-UBSAN
|
||||
// CHECK-RECOVER-UBSAN: "-fsanitize-recover={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift-base|shift-exponent|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){18}"}}
|
||||
// CHECK-RECOVER-UBSAN: "-fsanitize-recover={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){17}"}}
|
||||
// CHECK-NO-RECOVER-UBSAN-NOT: sanitize-recover
|
||||
|
||||
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=all -fsanitize-recover=object-size,shift-base -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-RECOVER
|
||||
|
@ -749,7 +749,7 @@
|
|||
// CHECK-TSAN-MINIMAL: error: invalid argument '-fsanitize-minimal-runtime' not allowed with '-fsanitize=thread'
|
||||
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-MINIMAL
|
||||
// CHECK-UBSAN-MINIMAL: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){19}"}}
|
||||
// CHECK-UBSAN-MINIMAL: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}}
|
||||
// CHECK-UBSAN-MINIMAL: "-fsanitize-minimal-runtime"
|
||||
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize=vptr -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-VPTR-MINIMAL
|
||||
|
|
|
@ -425,7 +425,7 @@ namespace compound_assign {
|
|||
constexpr bool test_overflow() {
|
||||
T a = 1;
|
||||
while (a != a / 2)
|
||||
a *= 2; // expected-note {{value 2147483648 is outside the range}} expected-note {{ 9223372036854775808 }} expected-note {{floating point arithmetic produces an infinity}}
|
||||
a *= 2; // expected-note {{value 2147483648 is outside the range}} expected-note {{ 9223372036854775808 }}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -435,7 +435,8 @@ namespace compound_assign {
|
|||
static_assert(test_overflow<unsigned short>(), ""); // ok
|
||||
static_assert(test_overflow<unsigned long long>(), ""); // ok
|
||||
static_assert(test_overflow<long long>(), ""); // expected-error {{constant}} expected-note {{call}}
|
||||
static_assert(test_overflow<float>(), ""); // expected-error {{constant}} expected-note {{call}}
|
||||
static_assert(test_overflow<float>(), ""); // ok
|
||||
static_assert(test_overflow<double>(), ""); // ok
|
||||
|
||||
constexpr short test_promotion(short k) {
|
||||
short s = k;
|
||||
|
|
Loading…
Reference in New Issue