Add -fsanitize=integer for reporting suspicious integer behaviors.

Introduces new sanitizer "unsigned-integer-overflow".

llvm-svn: 168701
This commit is contained in:
Will Dietz 2012-11-27 15:01:55 +00:00
parent 2631aaf939
commit 1897cb3b9c
10 changed files with 405 additions and 46 deletions

View File

@ -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>:

View File

@ -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

View File

@ -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))

View File

@ -30,7 +30,7 @@ class SanitizerArgs {
#include "clang/Basic/Sanitizers.def"
NeedsAsanRt = Address,
NeedsTsanRt = Thread,
NeedsUbsanRt = Undefined ^ Bounds
NeedsUbsanRt = (Undefined & ~Bounds) | Integer
};
unsigned Kind;

View File

@ -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

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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