forked from OSchip/llvm-project
Add -fsanitize=integer for reporting suspicious integer behaviors.
Introduces new sanitizer "unsigned-integer-overflow". llvm-svn: 168701
This commit is contained in:
parent
2631aaf939
commit
1897cb3b9c
|
@ -875,21 +875,27 @@ likely to affect PCH files that reference a large number of headers.</p>
|
|||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dl>
|
||||
<dt id="opt_fsanitize"><b>-fsanitize=check1,check2</b>: Turn on runtime checks
|
||||
for various forms of undefined behavior.</dt>
|
||||
for various forms of undefined or suspicious behavior.</dt>
|
||||
|
||||
<dd>This option controls whether Clang adds runtime checks for various forms of
|
||||
undefined behavior, and is disabled by default. If a check fails, a diagnostic
|
||||
message is produced at runtime explaining the problem. The main checks are:
|
||||
undefined or suspicious behavior, and is disabled by default. If a check
|
||||
fails, a diagnostic message is produced at runtime explaining the problem. The
|
||||
main checks are:
|
||||
|
||||
<ul>
|
||||
<li id="opt_fsanitize_address"><tt>-fsanitize=address</tt>:
|
||||
<a href="AddressSanitizer.html">AddressSanitizer</a>, a memory error
|
||||
detector.</li>
|
||||
<li id="opt_fsanitize_integer"><tt>-fsanitize=integer</tt>:
|
||||
Enables checks for undefined or suspicious integer behavior.</li>
|
||||
<li id="opt_fsanitize_thread"><tt>-fsanitize=thread</tt>:
|
||||
<a href="ThreadSanitizer.html">ThreadSanitizer</a>, an <em>experimental</em>
|
||||
data race detector. Not ready for widespread use.</li>
|
||||
<li id="opt_fsanitize_undefined"><tt>-fsanitize=undefined</tt>:
|
||||
Enables all the checks listed below.</li>
|
||||
Fast and compatible undefined behavior checker. Enables the undefined behavior
|
||||
checks that have small runtime cost and no impact on address space layout
|
||||
or ABI. This includes all of the checks listed below other than unsigned
|
||||
integer overflow.</li>
|
||||
</ul>
|
||||
|
||||
The following more fine-grained checks are also available:
|
||||
|
@ -897,11 +903,13 @@ The following more fine-grained checks are also available:
|
|||
<ul>
|
||||
<li id="opt_fsanitize_alignment"><tt>-fsanitize=alignment</tt>:
|
||||
Use of a misaligned pointer or creation of a misaligned reference.</li>
|
||||
<li id="opt_fsanitize_divide-by-zero"><tt>-fsanitize=divide-by-zero</tt>:
|
||||
Division by zero.</li>
|
||||
<li id="opt_fsanitize_float-cast-overflow"><tt>-fsanitize=float-cast-overflow</tt>:
|
||||
Conversion to, from, or between floating-point types which would overflow
|
||||
the destination.</li>
|
||||
<li id="opt_fsanitize_float-divide-by-zero"><tt>-fsanitize=float-divide-by-zero</tt>:
|
||||
Floating point division by zero.</li>
|
||||
<li id="opt_fsanitize_integer-divide-by-zero"><tt>-fsanitize=integer-divide-by-zero</tt>:
|
||||
Integer division by zero.</li>
|
||||
<li id="opt_fsanitize_null"><tt>-fsanitize=null</tt>:
|
||||
Use of a null pointer or creation of a null reference.</li>
|
||||
<li id="opt_fsanitize_object-size"><tt>-fsanitize=object-size</tt>:
|
||||
|
@ -923,6 +931,8 @@ The following more fine-grained checks are also available:
|
|||
and checking for overflow in signed division (<tt>INT_MIN / -1</tt>).</li>
|
||||
<li id="opt_fsanitize_unreachable"><tt>-fsanitize=unreachable</tt>:
|
||||
If control flow reaches __builtin_unreachable.</li>
|
||||
<li id="opt_fsanitize_unsigned-integer-overflow"><tt>-fsanitize=unsigned-integer-overflow</tt>:
|
||||
Unsigned integer overflows.</li>
|
||||
<li id="opt_fsanitize_vla-bound"><tt>-fsanitize=vla-bound</tt>:
|
||||
A variable-length array whose bound does not evaluate to a positive value.</li>
|
||||
<li id="opt_fsanitize_vptr"><tt>-fsanitize=vptr</tt>:
|
||||
|
|
|
@ -45,26 +45,34 @@ SANITIZER("address", Address)
|
|||
SANITIZER("thread", Thread)
|
||||
|
||||
// UndefinedBehaviorSanitizer
|
||||
SANITIZER("signed-integer-overflow", SignedIntegerOverflow)
|
||||
SANITIZER("divide-by-zero", DivideByZero)
|
||||
SANITIZER("shift", Shift)
|
||||
SANITIZER("unreachable", Unreachable)
|
||||
SANITIZER("return", Return)
|
||||
SANITIZER("vla-bound", VLABound)
|
||||
SANITIZER("alignment", Alignment)
|
||||
SANITIZER("null", Null)
|
||||
SANITIZER("vptr", Vptr)
|
||||
SANITIZER("object-size", ObjectSize)
|
||||
SANITIZER("float-cast-overflow", FloatCastOverflow)
|
||||
SANITIZER("bounds", Bounds)
|
||||
SANITIZER("float-cast-overflow", FloatCastOverflow)
|
||||
SANITIZER("float-divide-by-zero", FloatDivideByZero)
|
||||
SANITIZER("integer-divide-by-zero", IntegerDivideByZero)
|
||||
SANITIZER("null", Null)
|
||||
SANITIZER("object-size", ObjectSize)
|
||||
SANITIZER("return", Return)
|
||||
SANITIZER("shift", Shift)
|
||||
SANITIZER("signed-integer-overflow", SignedIntegerOverflow)
|
||||
SANITIZER("unreachable", Unreachable)
|
||||
SANITIZER("vla-bound", VLABound)
|
||||
SANITIZER("vptr", Vptr)
|
||||
|
||||
// IntegerSanitizer
|
||||
SANITIZER("unsigned-integer-overflow", UnsignedIntegerOverflow)
|
||||
|
||||
// -fsanitize=undefined (and its alias -fcatch-undefined-behavior). This should
|
||||
// include all the sanitizers which have low overhead, no ABI or address space
|
||||
// layout implications, and only catch undefined behavior.
|
||||
SANITIZER_GROUP("undefined", Undefined,
|
||||
SignedIntegerOverflow | DivideByZero | Shift | Unreachable |
|
||||
Return | VLABound | Alignment | Null | Vptr | ObjectSize |
|
||||
FloatCastOverflow | Bounds)
|
||||
Alignment | Bounds | FloatCastOverflow | FloatDivideByZero |
|
||||
IntegerDivideByZero | Null | ObjectSize | Return | Shift |
|
||||
SignedIntegerOverflow | Unreachable | VLABound | Vptr)
|
||||
|
||||
SANITIZER_GROUP("integer", Integer,
|
||||
SignedIntegerOverflow | UnsignedIntegerOverflow | Shift |
|
||||
IntegerDivideByZero)
|
||||
|
||||
#undef SANITIZER
|
||||
#undef SANITIZER_GROUP
|
||||
|
|
|
@ -414,6 +414,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
if (Ops.Ty->isUnsignedIntegerType() &&
|
||||
CGF.getLangOpts().SanitizeUnsignedIntegerOverflow)
|
||||
return EmitOverflowCheckedBinOp(Ops);
|
||||
|
||||
if (Ops.LHS->getType()->isFPOrFPVectorTy())
|
||||
return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
|
||||
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
|
||||
|
@ -1472,11 +1476,23 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
|
|||
|
||||
// Note that signed integer inc/dec with width less than int can't
|
||||
// overflow because of promotion rules; we're just eliding a few steps here.
|
||||
if (type->isSignedIntegerOrEnumerationType() &&
|
||||
value->getType()->getPrimitiveSizeInBits() >=
|
||||
CGF.IntTy->getBitWidth())
|
||||
if (value->getType()->getPrimitiveSizeInBits() >=
|
||||
CGF.IntTy->getBitWidth() &&
|
||||
type->isSignedIntegerOrEnumerationType()) {
|
||||
value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc);
|
||||
else
|
||||
} else if (value->getType()->getPrimitiveSizeInBits() >=
|
||||
CGF.IntTy->getBitWidth() &&
|
||||
type->isUnsignedIntegerType() &&
|
||||
CGF.getLangOpts().SanitizeUnsignedIntegerOverflow) {
|
||||
BinOpInfo BinOp;
|
||||
BinOp.LHS = value;
|
||||
BinOp.RHS = llvm::ConstantInt::get(value->getType(), 1, false);
|
||||
BinOp.Ty = E->getType();
|
||||
BinOp.Opcode = isInc ? BO_Add : BO_Sub;
|
||||
BinOp.FPContractable = false;
|
||||
BinOp.E = E;
|
||||
value = EmitOverflowCheckedBinOp(BinOp);
|
||||
} else
|
||||
value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
|
||||
|
||||
// Next most common: pointer increment.
|
||||
|
@ -1926,7 +1942,7 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
|
|||
const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) {
|
||||
llvm::Value *Cond = 0;
|
||||
|
||||
if (CGF.getLangOpts().SanitizeDivideByZero)
|
||||
if (CGF.getLangOpts().SanitizeIntegerDivideByZero)
|
||||
Cond = Builder.CreateICmpNE(Ops.RHS, Zero);
|
||||
|
||||
if (CGF.getLangOpts().SanitizeSignedIntegerOverflow &&
|
||||
|
@ -1948,16 +1964,17 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
|
|||
}
|
||||
|
||||
Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
|
||||
if (CGF.getLangOpts().SanitizeDivideByZero ||
|
||||
CGF.getLangOpts().SanitizeSignedIntegerOverflow) {
|
||||
if ((CGF.getLangOpts().SanitizeIntegerDivideByZero ||
|
||||
CGF.getLangOpts().SanitizeSignedIntegerOverflow) &&
|
||||
Ops.Ty->isIntegerType()) {
|
||||
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
|
||||
|
||||
if (Ops.Ty->isIntegerType())
|
||||
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
|
||||
else if (CGF.getLangOpts().SanitizeDivideByZero &&
|
||||
Ops.Ty->isRealFloatingType())
|
||||
EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops);
|
||||
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
|
||||
} else if (CGF.getLangOpts().SanitizeFloatDivideByZero &&
|
||||
Ops.Ty->isRealFloatingType()) {
|
||||
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
|
||||
EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops);
|
||||
}
|
||||
|
||||
if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
|
||||
llvm::Value *Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
|
||||
if (CGF.getLangOpts().OpenCL) {
|
||||
|
@ -1978,10 +1995,10 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
|
|||
|
||||
Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) {
|
||||
// Rem in C can't be a floating point type: C99 6.5.5p2.
|
||||
if (CGF.getLangOpts().SanitizeDivideByZero) {
|
||||
if (CGF.getLangOpts().SanitizeIntegerDivideByZero) {
|
||||
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
|
||||
|
||||
if (Ops.Ty->isIntegerType())
|
||||
if (Ops.Ty->isIntegerType())
|
||||
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, false);
|
||||
}
|
||||
|
||||
|
@ -1995,27 +2012,32 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
|
|||
unsigned IID;
|
||||
unsigned OpID = 0;
|
||||
|
||||
bool isSigned = Ops.Ty->isSignedIntegerOrEnumerationType();
|
||||
switch (Ops.Opcode) {
|
||||
case BO_Add:
|
||||
case BO_AddAssign:
|
||||
OpID = 1;
|
||||
IID = llvm::Intrinsic::sadd_with_overflow;
|
||||
IID = isSigned ? llvm::Intrinsic::sadd_with_overflow :
|
||||
llvm::Intrinsic::uadd_with_overflow;
|
||||
break;
|
||||
case BO_Sub:
|
||||
case BO_SubAssign:
|
||||
OpID = 2;
|
||||
IID = llvm::Intrinsic::ssub_with_overflow;
|
||||
IID = isSigned ? llvm::Intrinsic::ssub_with_overflow :
|
||||
llvm::Intrinsic::usub_with_overflow;
|
||||
break;
|
||||
case BO_Mul:
|
||||
case BO_MulAssign:
|
||||
OpID = 3;
|
||||
IID = llvm::Intrinsic::smul_with_overflow;
|
||||
IID = isSigned ? llvm::Intrinsic::smul_with_overflow :
|
||||
llvm::Intrinsic::umul_with_overflow;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unsupported operation for overflow detection");
|
||||
}
|
||||
OpID <<= 1;
|
||||
OpID |= 1;
|
||||
if (isSigned)
|
||||
OpID |= 1;
|
||||
|
||||
llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ops.Ty);
|
||||
|
||||
|
@ -2031,7 +2053,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
|
|||
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 (CGF.getLangOpts().SanitizeSignedIntegerOverflow)
|
||||
if (!isSigned || CGF.getLangOpts().SanitizeSignedIntegerOverflow)
|
||||
EmitBinOpCheck(Builder.CreateNot(overflow), Ops);
|
||||
else
|
||||
CGF.EmitTrapvCheck(Builder.CreateNot(overflow));
|
||||
|
@ -2256,7 +2278,11 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
|
|||
return EmitOverflowCheckedBinOp(op);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (op.Ty->isUnsignedIntegerType() &&
|
||||
CGF.getLangOpts().SanitizeUnsignedIntegerOverflow)
|
||||
return EmitOverflowCheckedBinOp(op);
|
||||
|
||||
if (op.LHS->getType()->isFPOrFPVectorTy()) {
|
||||
// Try to form an fmuladd.
|
||||
if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder))
|
||||
|
@ -2283,7 +2309,11 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
|
|||
return EmitOverflowCheckedBinOp(op);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (op.Ty->isUnsignedIntegerType() &&
|
||||
CGF.getLangOpts().SanitizeUnsignedIntegerOverflow)
|
||||
return EmitOverflowCheckedBinOp(op);
|
||||
|
||||
if (op.LHS->getType()->isFPOrFPVectorTy()) {
|
||||
// Try to form an fmuladd.
|
||||
if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true))
|
||||
|
|
|
@ -30,7 +30,7 @@ class SanitizerArgs {
|
|||
#include "clang/Basic/Sanitizers.def"
|
||||
NeedsAsanRt = Address,
|
||||
NeedsTsanRt = Thread,
|
||||
NeedsUbsanRt = Undefined ^ Bounds
|
||||
NeedsUbsanRt = (Undefined & ~Bounds) | Integer
|
||||
};
|
||||
unsigned Kind;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -fsanitize=alignment,null,object-size,shift,return,signed-integer-overflow,vla-bound,float-cast-overflow,divide-by-zero -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
|
||||
// RUN: %clang_cc1 -fsanitize=alignment,null,object-size,shift,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
|
||||
// RUN: %clang_cc1 -fsanitize=null -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-NULL
|
||||
// RUN: %clang_cc1 -fsanitize=signed-integer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-OVERFLOW
|
||||
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsanitize=unsigned-integer-overflow %s -emit-llvm -o - | FileCheck %s
|
||||
// Verify checked operations are emitted for integers and longs.
|
||||
// unsigned short/char's tested in unsigned-promotion.c
|
||||
|
||||
unsigned long li, lj, lk;
|
||||
unsigned int ii, ij, ik;
|
||||
|
||||
extern void opaquelong(unsigned long);
|
||||
extern void opaqueint(unsigned int);
|
||||
|
||||
// CHECK: define void @testlongadd()
|
||||
void testlongadd() {
|
||||
|
||||
// CHECK: [[T1:%.*]] = load i64* @lj
|
||||
// CHECK-NEXT: [[T2:%.*]] = load i64* @lk
|
||||
// CHECK-NEXT: [[T3:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[T1]], i64 [[T2]])
|
||||
// CHECK-NEXT: [[T4:%.*]] = extractvalue { i64, i1 } [[T3]], 0
|
||||
// CHECK-NEXT: [[T5:%.*]] = extractvalue { i64, i1 } [[T3]], 1
|
||||
// CHECK: call void @__ubsan_handle_add_overflow
|
||||
li = lj + lk;
|
||||
}
|
||||
|
||||
// CHECK: define void @testlongsub()
|
||||
void testlongsub() {
|
||||
|
||||
// CHECK: [[T1:%.*]] = load i64* @lj
|
||||
// CHECK-NEXT: [[T2:%.*]] = load i64* @lk
|
||||
// CHECK-NEXT: [[T3:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[T1]], i64 [[T2]])
|
||||
// CHECK-NEXT: [[T4:%.*]] = extractvalue { i64, i1 } [[T3]], 0
|
||||
// CHECK-NEXT: [[T5:%.*]] = extractvalue { i64, i1 } [[T3]], 1
|
||||
// CHECK: call void @__ubsan_handle_sub_overflow
|
||||
li = lj - lk;
|
||||
}
|
||||
|
||||
// CHECK: define void @testlongmul()
|
||||
void testlongmul() {
|
||||
|
||||
// CHECK: [[T1:%.*]] = load i64* @lj
|
||||
// CHECK-NEXT: [[T2:%.*]] = load i64* @lk
|
||||
// CHECK-NEXT: [[T3:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[T1]], i64 [[T2]])
|
||||
// CHECK-NEXT: [[T4:%.*]] = extractvalue { i64, i1 } [[T3]], 0
|
||||
// CHECK-NEXT: [[T5:%.*]] = extractvalue { i64, i1 } [[T3]], 1
|
||||
// CHECK: call void @__ubsan_handle_mul_overflow
|
||||
li = lj * lk;
|
||||
}
|
||||
|
||||
// CHECK: define void @testlongpostinc()
|
||||
void testlongpostinc() {
|
||||
opaquelong(li++);
|
||||
|
||||
// CHECK: [[T1:%.*]] = load i64* @li
|
||||
// CHECK-NEXT: [[T2:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[T1]], i64 1)
|
||||
// CHECK-NEXT: [[T3:%.*]] = extractvalue { i64, i1 } [[T2]], 0
|
||||
// CHECK-NEXT: [[T4:%.*]] = extractvalue { i64, i1 } [[T2]], 1
|
||||
// CHECK: call void @__ubsan_handle_add_overflow
|
||||
}
|
||||
|
||||
// CHECK: define void @testlongpreinc()
|
||||
void testlongpreinc() {
|
||||
opaquelong(++li);
|
||||
|
||||
// CHECK: [[T1:%.*]] = load i64* @li
|
||||
// CHECK-NEXT: [[T2:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[T1]], i64 1)
|
||||
// CHECK-NEXT: [[T3:%.*]] = extractvalue { i64, i1 } [[T2]], 0
|
||||
// CHECK-NEXT: [[T4:%.*]] = extractvalue { i64, i1 } [[T2]], 1
|
||||
// CHECK: call void @__ubsan_handle_add_overflow
|
||||
}
|
||||
|
||||
// CHECK: define void @testintadd()
|
||||
void testintadd() {
|
||||
|
||||
// CHECK: [[T1:%.*]] = load i32* @ij
|
||||
// CHECK-NEXT: [[T2:%.*]] = load i32* @ik
|
||||
// CHECK-NEXT: [[T3:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[T1]], i32 [[T2]])
|
||||
// CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T3]], 0
|
||||
// CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T3]], 1
|
||||
// CHECK: call void @__ubsan_handle_add_overflow
|
||||
ii = ij + ik;
|
||||
}
|
||||
|
||||
// CHECK: define void @testintsub()
|
||||
void testintsub() {
|
||||
|
||||
// CHECK: [[T1:%.*]] = load i32* @ij
|
||||
// CHECK-NEXT: [[T2:%.*]] = load i32* @ik
|
||||
// CHECK-NEXT: [[T3:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[T1]], i32 [[T2]])
|
||||
// CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T3]], 0
|
||||
// CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T3]], 1
|
||||
// CHECK: call void @__ubsan_handle_sub_overflow
|
||||
ii = ij - ik;
|
||||
}
|
||||
|
||||
// CHECK: define void @testintmul()
|
||||
void testintmul() {
|
||||
|
||||
// CHECK: [[T1:%.*]] = load i32* @ij
|
||||
// CHECK-NEXT: [[T2:%.*]] = load i32* @ik
|
||||
// CHECK-NEXT: [[T3:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[T1]], i32 [[T2]])
|
||||
// CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T3]], 0
|
||||
// CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T3]], 1
|
||||
// CHECK: call void @__ubsan_handle_mul_overflow
|
||||
ii = ij * ik;
|
||||
}
|
||||
|
||||
// CHECK: define void @testintpostinc()
|
||||
void testintpostinc() {
|
||||
opaqueint(ii++);
|
||||
|
||||
// CHECK: [[T1:%.*]] = load i32* @ii
|
||||
// CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[T1]], i32 1)
|
||||
// CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 0
|
||||
// CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T2]], 1
|
||||
// CHECK: call void @__ubsan_handle_add_overflow
|
||||
}
|
||||
|
||||
// CHECK: define void @testintpreinc()
|
||||
void testintpreinc() {
|
||||
opaqueint(++ii);
|
||||
|
||||
// CHECK: [[T1:%.*]] = load i32* @ii
|
||||
// CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[T1]], i32 1)
|
||||
// CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 0
|
||||
// CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T2]], 1
|
||||
// CHECK: call void @__ubsan_handle_add_overflow
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
// Check -fsanitize=signed-integer-overflow and
|
||||
// -fsanitize=unsigned-integer-overflow with promoted unsigned types
|
||||
//
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s \
|
||||
// RUN: -fsanitize=signed-integer-overflow | FileCheck %s --check-prefix=CHECKS
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s \
|
||||
// RUN: -fsanitize=unsigned-integer-overflow | FileCheck %s --check-prefix=CHECKU
|
||||
|
||||
unsigned short si, sj, sk;
|
||||
unsigned char ci, cj, ck;
|
||||
|
||||
extern void opaqueshort(unsigned short);
|
||||
extern void opaquechar(unsigned char);
|
||||
|
||||
// CHECKS: define void @testshortadd()
|
||||
// CHECKU: define void @testshortadd()
|
||||
void testshortadd() {
|
||||
// CHECKS: load i16* @sj
|
||||
// CHECKS: load i16* @sk
|
||||
// CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
|
||||
// CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
|
||||
// CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
|
||||
// CHECKS: call void @__ubsan_handle_add_overflow
|
||||
//
|
||||
// CHECKU: [[T1:%.*]] = load i16* @sj
|
||||
// CHECKU: [[T2:%.*]] = zext i16 [[T1]]
|
||||
// CHECKU: [[T3:%.*]] = load i16* @sk
|
||||
// CHECKU: [[T4:%.*]] = zext i16 [[T3]]
|
||||
// CHECKU-NOT: llvm.sadd
|
||||
// CHECKU-NOT: llvm.uadd
|
||||
// CHECKU: [[T5:%.*]] = add nsw i32 [[T2]], [[T4]]
|
||||
|
||||
si = sj + sk;
|
||||
}
|
||||
|
||||
// CHECKS: define void @testshortsub()
|
||||
// CHECKU: define void @testshortsub()
|
||||
void testshortsub() {
|
||||
|
||||
// CHECKS: load i16* @sj
|
||||
// CHECKS: load i16* @sk
|
||||
// CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
|
||||
// CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
|
||||
// CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
|
||||
// CHECKS: call void @__ubsan_handle_sub_overflow
|
||||
//
|
||||
// CHECKU: [[T1:%.*]] = load i16* @sj
|
||||
// CHECKU: [[T2:%.*]] = zext i16 [[T1]]
|
||||
// CHECKU: [[T3:%.*]] = load i16* @sk
|
||||
// CHECKU: [[T4:%.*]] = zext i16 [[T3]]
|
||||
// CHECKU-NOT: llvm.ssub
|
||||
// CHECKU-NOT: llvm.usub
|
||||
// CHECKU: [[T5:%.*]] = sub nsw i32 [[T2]], [[T4]]
|
||||
|
||||
si = sj - sk;
|
||||
}
|
||||
|
||||
// CHECKS: define void @testshortmul()
|
||||
// CHECKU: define void @testshortmul()
|
||||
void testshortmul() {
|
||||
|
||||
// CHECKS: load i16* @sj
|
||||
// CHECKS: load i16* @sk
|
||||
// CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
|
||||
// CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
|
||||
// CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
|
||||
// CHECKS: call void @__ubsan_handle_mul_overflow
|
||||
//
|
||||
// CHECKU: [[T1:%.*]] = load i16* @sj
|
||||
// CHECKU: [[T2:%.*]] = zext i16 [[T1]]
|
||||
// CHECKU: [[T3:%.*]] = load i16* @sk
|
||||
// CHECKU: [[T4:%.*]] = zext i16 [[T3]]
|
||||
// CHECKU-NOT: llvm.smul
|
||||
// CHECKU-NOT: llvm.umul
|
||||
// CHECKU: [[T5:%.*]] = mul nsw i32 [[T2]], [[T4]]
|
||||
si = sj * sk;
|
||||
}
|
||||
|
||||
// CHECKS: define void @testcharadd()
|
||||
// CHECKU: define void @testcharadd()
|
||||
void testcharadd() {
|
||||
|
||||
// CHECKS: load i8* @cj
|
||||
// CHECKS: load i8* @ck
|
||||
// CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
|
||||
// CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
|
||||
// CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
|
||||
// CHECKS: call void @__ubsan_handle_add_overflow
|
||||
//
|
||||
// CHECKU: [[T1:%.*]] = load i8* @cj
|
||||
// CHECKU: [[T2:%.*]] = zext i8 [[T1]]
|
||||
// CHECKU: [[T3:%.*]] = load i8* @ck
|
||||
// CHECKU: [[T4:%.*]] = zext i8 [[T3]]
|
||||
// CHECKU-NOT: llvm.sadd
|
||||
// CHECKU-NOT: llvm.uadd
|
||||
// CHECKU: [[T5:%.*]] = add nsw i32 [[T2]], [[T4]]
|
||||
|
||||
ci = cj + ck;
|
||||
}
|
||||
|
||||
// CHECKS: define void @testcharsub()
|
||||
// CHECKU: define void @testcharsub()
|
||||
void testcharsub() {
|
||||
|
||||
// CHECKS: load i8* @cj
|
||||
// CHECKS: load i8* @ck
|
||||
// CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
|
||||
// CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
|
||||
// CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
|
||||
// CHECKS: call void @__ubsan_handle_sub_overflow
|
||||
//
|
||||
// CHECKU: [[T1:%.*]] = load i8* @cj
|
||||
// CHECKU: [[T2:%.*]] = zext i8 [[T1]]
|
||||
// CHECKU: [[T3:%.*]] = load i8* @ck
|
||||
// CHECKU: [[T4:%.*]] = zext i8 [[T3]]
|
||||
// CHECKU-NOT: llvm.ssub
|
||||
// CHECKU-NOT: llvm.usub
|
||||
// CHECKU: [[T5:%.*]] = sub nsw i32 [[T2]], [[T4]]
|
||||
|
||||
ci = cj - ck;
|
||||
}
|
||||
|
||||
// CHECKS: define void @testcharmul()
|
||||
// CHECKU: define void @testcharmul()
|
||||
void testcharmul() {
|
||||
|
||||
// CHECKS: load i8* @cj
|
||||
// CHECKS: load i8* @ck
|
||||
// CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
|
||||
// CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
|
||||
// CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
|
||||
// CHECKS: call void @__ubsan_handle_mul_overflow
|
||||
//
|
||||
// CHECKU: [[T1:%.*]] = load i8* @cj
|
||||
// CHECKU: [[T2:%.*]] = zext i8 [[T1]]
|
||||
// CHECKU: [[T3:%.*]] = load i8* @ck
|
||||
// CHECKU: [[T4:%.*]] = zext i8 [[T3]]
|
||||
// CHECKU-NOT: llvm.smul
|
||||
// CHECKU-NOT: llvm.umul
|
||||
// CHECKU: [[T5:%.*]] = mul nsw i32 [[T2]], [[T4]]
|
||||
|
||||
ci = cj * ck;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fsanitize=unsigned-integer-overflow | FileCheck %s --check-prefix=UNSIGNED
|
||||
// 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=unsigned-integer-overflow -ftrapv | FileCheck %s --check-prefix=BOTH
|
||||
// Verify that -ftrapv and -fsanitize=unsigned-integer-overflow
|
||||
// work together as expected
|
||||
|
||||
|
||||
// UNSIGNED: @test_signed
|
||||
// TRAPV: @test_signed
|
||||
// BOTH: @test_signed
|
||||
void test_signed() {
|
||||
extern volatile int a, b, c;
|
||||
// UNSIGNED: add nsw i32
|
||||
// UNSIGNED-NOT: overflow
|
||||
// TRAPV: sadd.with.overflow.i32
|
||||
// TRAPV-NOT: ubsan
|
||||
// TRAPV: llvm.trap
|
||||
// BOTH: sadd.with.overflow.i32
|
||||
// BOTH-NOT: ubsan
|
||||
// BOTH: llvm.trap
|
||||
a = b + c;
|
||||
}
|
||||
|
||||
// UNSIGNED: @test_unsigned
|
||||
// TRAPV: @test_unsigned
|
||||
// BOTH: @test_unsigned
|
||||
void test_unsigned() {
|
||||
extern volatile unsigned x, y, z;
|
||||
// UNSIGNED: uadd.with.overflow.i32
|
||||
// UNSIGNED-NOT: llvm.trap
|
||||
// UNSIGNED: ubsan
|
||||
// TRAPV-NOT: overflow
|
||||
// TRAPV-NOT: llvm.trap
|
||||
// BOTH: uadd.with.overflow.i32
|
||||
// BOTH: ubsan
|
||||
// BOTH-NOT: llvm.trap
|
||||
x = y + z;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -fsanitize=signed-integer-overflow,divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
|
||||
// RUN: %clang_cc1 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
|
||||
|
||||
// CHECK: @_Z17reference_binding
|
||||
void reference_binding(int *p) {
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
// RUN: %clang -target x86_64-linux-gnu -fcatch-undefined-behavior %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
|
||||
// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|bounds),?){12}"}}
|
||||
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread,undefined -fno-thread-sanitizer -fno-sanitize=float-cast-overflow,vptr %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-UNDEFINED
|
||||
// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|object-size|bounds),?){10}"}}
|
||||
// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|bounds),?){13}"}}
|
||||
//
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=integer %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INTEGER
|
||||
// CHECK-INTEGER: "-fsanitize={{((signed-integer-overflow|unsigned-integer-overflow|integer-divide-by-zero|shift),?){4}"}}
|
||||
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread,undefined -fno-thread-sanitizer -fno-sanitize=float-cast-overflow,vptr %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|shift|unreachable|return|vla-bound|alignment|null|object-size|bounds),?){11}"}}
|
||||
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fno-rtti %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-RTTI
|
||||
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fno-rtti %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-RTTI
|
||||
|
|
Loading…
Reference in New Issue