[cfe-commits] r165536 - in /cfe/trunk: include/clang/Basic/Diagnostic.h lib/CodeGen/CGBuiltin.cpp lib/CodeGen/CGClass.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprCXX.cpp lib/CodeGen/CGExprScalar.cpp lib/CodeGen/CodeGenFunction.cpp lib/CodeGen/CodeGenFunction.h lib/Driver/Tools.cpp test/CodeGen/catch-undef-behavior.c test/CodeGen/trapv.c test/CodeGenCXX/catch-undef-behavior.cpp
Richard Smith
richard-llvm at metafoo.co.uk
Tue Oct 9 12:52:38 PDT 2012
Author: rsmith
Date: Tue Oct 9 14:52:38 2012
New Revision: 165536
URL: http://llvm.org/viewvc/llvm-project?rev=165536&view=rev
Log:
-fcatch-undefined-behavior: emit calls to the runtime library whenever one of the checks fails.
Modified:
cfe/trunk/include/clang/Basic/Diagnostic.h
cfe/trunk/lib/CodeGen/CGBuiltin.cpp
cfe/trunk/lib/CodeGen/CGClass.cpp
cfe/trunk/lib/CodeGen/CGExpr.cpp
cfe/trunk/lib/CodeGen/CGExprAgg.cpp
cfe/trunk/lib/CodeGen/CGExprCXX.cpp
cfe/trunk/lib/CodeGen/CGExprScalar.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/lib/Driver/Tools.cpp
cfe/trunk/test/CodeGen/catch-undef-behavior.c
cfe/trunk/test/CodeGen/trapv.c
cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp
Modified: cfe/trunk/include/clang/Basic/Diagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Diagnostic.h?rev=165536&r1=165535&r2=165536&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Diagnostic.h (original)
+++ cfe/trunk/include/clang/Basic/Diagnostic.h Tue Oct 9 14:52:38 2012
@@ -587,7 +587,7 @@
const char *Argument, unsigned ArgLen,
const ArgumentValue *PrevArgs, unsigned NumPrevArgs,
SmallVectorImpl<char> &Output,
- SmallVectorImpl<intptr_t> &QualTypeVals) const {
+ ArrayRef<intptr_t> QualTypeVals) const {
ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen,
PrevArgs, NumPrevArgs, Output, ArgToStringCookie,
QualTypeVals);
Modified: cfe/trunk/lib/CodeGen/CGBuiltin.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuiltin.cpp?rev=165536&r1=165535&r2=165536&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBuiltin.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp Tue Oct 9 14:52:38 2012
@@ -409,7 +409,9 @@
}
case Builtin::BI__builtin_unreachable: {
if (CatchUndefined)
- EmitCheck(Builder.getFalse());
+ EmitCheck(Builder.getFalse(), "builtin_unreachable",
+ EmitCheckSourceLocation(E->getExprLoc()),
+ llvm::ArrayRef<llvm::Value *>());
else
Builder.CreateUnreachable();
Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=165536&r1=165535&r2=165536&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Tue Oct 9 14:52:38 2012
@@ -1268,7 +1268,9 @@
llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase);
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
- EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd);
+ // FIXME: Provide a source location here.
+ EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
+ VTT, ArgBeg, ArgEnd);
}
void
@@ -1420,7 +1422,9 @@
if (!Callee)
Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
- EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0);
+ // FIXME: Provide a source location here.
+ EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
+ VTT, 0, 0);
}
namespace {
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=165536&r1=165535&r2=165536&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Tue Oct 9 14:52:38 2012
@@ -493,7 +493,7 @@
// storage of suitable size and alignment to contain an object of the
// reference's type, the behavior is undefined.
QualType Ty = E->getType();
- EmitTypeCheck(TCK_ReferenceBinding, Value, Ty);
+ EmitTypeCheck(TCK_ReferenceBinding, E->getExprLoc(), Value, Ty);
}
if (!ReferenceTemporaryDtor && ObjCARCReferenceLifetimeType.isNull())
return RValue::get(Value);
@@ -558,7 +558,8 @@
->getZExtValue();
}
-void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, llvm::Value *Address,
+void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
+ llvm::Value *Address,
QualType Ty, CharUnits Alignment) {
if (!CatchUndefined)
return;
@@ -573,9 +574,10 @@
Address, llvm::Constant::getNullValue(Address->getType()));
}
+ uint64_t AlignVal = Alignment.getQuantity();
+
if (!Ty->isIncompleteType()) {
uint64_t Size = getContext().getTypeSizeInChars(Ty).getQuantity();
- uint64_t AlignVal = Alignment.getQuantity();
if (!AlignVal)
AlignVal = getContext().getTypeAlignInChars(Ty).getQuantity();
@@ -591,7 +593,9 @@
Builder.CreateICmpUGE(Builder.CreateCall2(F, Address, Min),
llvm::ConstantInt::get(IntPtrTy, Size));
Cond = Cond ? Builder.CreateAnd(Cond, LargeEnough) : LargeEnough;
+ }
+ if (AlignVal) {
// The glvalue must be suitably aligned.
llvm::Value *Align =
Builder.CreateAnd(Builder.CreatePtrToInt(Address, IntPtrTy),
@@ -600,8 +604,15 @@
Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0)));
}
- if (Cond)
- EmitCheck(Cond);
+ if (Cond) {
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(Loc),
+ EmitCheckTypeDescriptor(Ty),
+ llvm::ConstantInt::get(SizeTy, AlignVal),
+ llvm::ConstantInt::get(Int8Ty, TCK)
+ };
+ EmitCheck(Cond, "type_mismatch", StaticData, Address);
+ }
}
@@ -681,7 +692,8 @@
LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) {
LValue LV = EmitLValue(E);
if (!isa<DeclRefExpr>(E) && !LV.isBitField() && LV.isSimple())
- EmitTypeCheck(TCK, LV.getAddress(), E->getType(), LV.getAlignment());
+ EmitTypeCheck(TCK, E->getExprLoc(), LV.getAddress(),
+ E->getType(), LV.getAlignment());
return LV;
}
@@ -1925,32 +1937,158 @@
}
}
-void CodeGenFunction::EmitCheck(llvm::Value *Checked) {
- const CodeGenOptions &GCO = CGM.getCodeGenOpts();
+/// Emit a type description suitable for use by a runtime sanitizer library. The
+/// format of a type descriptor is
+///
+/// \code
+/// { i8* Name, i16 TypeKind, i16 TypeInfo }
+/// \endcode
+///
+/// where TypeKind is 0 for an integer, 1 for a floating point value, and -1 for
+/// anything else.
+llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
+ // FIXME: Only emit each type's descriptor once.
+ uint16_t TypeKind = -1;
+ uint16_t TypeInfo = 0;
+
+ if (T->isIntegerType()) {
+ TypeKind = 0;
+ TypeInfo = (llvm::Log2_32(getContext().getTypeSize(T)) << 1) |
+ T->isSignedIntegerType();
+ } else if (T->isFloatingType()) {
+ TypeKind = 1;
+ TypeInfo = getContext().getTypeSize(T);
+ }
+
+ // Format the type name as if for a diagnostic, including quotes and
+ // optionally an 'aka'.
+ llvm::SmallString<32> Buffer;
+ CGM.getDiags().ConvertArgToString(DiagnosticsEngine::ak_qualtype,
+ (intptr_t)T.getAsOpaquePtr(),
+ 0, 0, 0, 0, 0, 0, Buffer,
+ ArrayRef<intptr_t>());
+
+ llvm::Constant *Components[] = {
+ cast<llvm::Constant>(Builder.CreateGlobalStringPtr(Buffer)),
+ Builder.getInt16(TypeKind), Builder.getInt16(TypeInfo)
+ };
+ llvm::Constant *Descriptor = llvm::ConstantStruct::getAnon(Components);
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(CGM.getModule(), Descriptor->getType(),
+ /*isConstant=*/true,
+ llvm::GlobalVariable::PrivateLinkage,
+ Descriptor);
+ GV->setUnnamedAddr(true);
+ return GV;
+}
+
+llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) {
+ llvm::Type *TargetTy = IntPtrTy;
+
+ // Integers which fit in intptr_t are zero-extended and passed directly.
+ if (V->getType()->isIntegerTy() &&
+ V->getType()->getIntegerBitWidth() <= TargetTy->getIntegerBitWidth())
+ return Builder.CreateZExt(V, TargetTy);
+
+ // Pointers are passed directly, everything else is passed by address.
+ if (!V->getType()->isPointerTy()) {
+ llvm::Value *Ptr = Builder.CreateAlloca(V->getType());
+ Builder.CreateStore(V, Ptr);
+ V = Ptr;
+ }
+ return Builder.CreatePtrToInt(V, TargetTy);
+}
+
+/// \brief Emit a representation of a SourceLocation for passing to a handler
+/// in a sanitizer runtime library. The format for this data is:
+/// \code
+/// struct SourceLocation {
+/// const char *Filename;
+/// int32_t Line, Column;
+/// };
+/// \endcode
+/// For an invalid SourceLocation, the Filename pointer is null.
+llvm::Constant *CodeGenFunction::EmitCheckSourceLocation(SourceLocation Loc) {
+ PresumedLoc PLoc = getContext().getSourceManager().getPresumedLoc(Loc);
+
+ llvm::Constant *Data[] = {
+ // FIXME: Only emit each file name once.
+ PLoc.isValid() ? cast<llvm::Constant>(
+ Builder.CreateGlobalStringPtr(PLoc.getFilename()))
+ : llvm::Constant::getNullValue(Int8PtrTy),
+ Builder.getInt32(PLoc.getLine()),
+ Builder.getInt32(PLoc.getColumn())
+ };
+
+ return llvm::ConstantStruct::getAnon(Data);
+}
+void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
+ llvm::ArrayRef<llvm::Constant *> StaticArgs,
+ llvm::ArrayRef<llvm::Value *> DynamicArgs) {
llvm::BasicBlock *Cont = createBasicBlock("cont");
- // If we are not optimzing, don't collapse all calls to trap in the function
- // to the same call, that way, in the debugger they can see which operation
- // did in fact fail. If we are optimizing, we collapse all calls to trap down
- // to just one per function to save on codesize.
- bool NeedNewTrapBB = !GCO.OptimizationLevel || !TrapBB;
-
- if (NeedNewTrapBB)
- TrapBB = createBasicBlock("trap");
-
- Builder.CreateCondBr(Checked, Cont, TrapBB);
-
- if (NeedNewTrapBB) {
- EmitBlock(TrapBB);
-
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap);
- llvm::CallInst *TrapCall = Builder.CreateCall(F);
- TrapCall->setDoesNotReturn();
- TrapCall->setDoesNotThrow();
- Builder.CreateUnreachable();
+ // If -fcatch-undefined-behavior is not enabled, just emit a trap. This
+ // happens when using -ftrapv.
+ // FIXME: Should -ftrapv require the ubsan runtime library?
+ if (!CatchUndefined) {
+ // If we're optimizing, collapse all calls to trap down to just one per
+ // function to save on code size.
+ if (!CGM.getCodeGenOpts().OptimizationLevel || !TrapBB) {
+ TrapBB = createBasicBlock("trap");
+ Builder.CreateCondBr(Checked, Cont, TrapBB);
+ EmitBlock(TrapBB);
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap);
+ llvm::CallInst *TrapCall = Builder.CreateCall(F);
+ TrapCall->setDoesNotReturn();
+ TrapCall->setDoesNotThrow();
+ Builder.CreateUnreachable();
+ } else {
+ Builder.CreateCondBr(Checked, Cont, TrapBB);
+ }
+
+ EmitBlock(Cont);
+ return;
}
+ llvm::BasicBlock *Handler = createBasicBlock("handler." + CheckName);
+ Builder.CreateCondBr(Checked, Cont, Handler);
+ EmitBlock(Handler);
+
+ llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
+ llvm::GlobalValue *InfoPtr =
+ new llvm::GlobalVariable(CGM.getModule(), Info->getType(), true,
+ llvm::GlobalVariable::PrivateLinkage, Info);
+ InfoPtr->setUnnamedAddr(true);
+
+ llvm::SmallVector<llvm::Value *, 4> Args;
+ llvm::SmallVector<llvm::Type *, 4> ArgTypes;
+ Args.reserve(DynamicArgs.size() + 1);
+ ArgTypes.reserve(DynamicArgs.size() + 1);
+
+ // Handler functions take an i8* pointing to the (handler-specific) static
+ // information block, followed by a sequence of intptr_t arguments
+ // representing operand values.
+ Args.push_back(Builder.CreateBitCast(InfoPtr, Int8PtrTy));
+ ArgTypes.push_back(Int8PtrTy);
+ for (size_t i = 0, n = DynamicArgs.size(); i != n; ++i) {
+ Args.push_back(EmitCheckValue(DynamicArgs[i]));
+ ArgTypes.push_back(IntPtrTy);
+ }
+
+ llvm::FunctionType *FnType =
+ llvm::FunctionType::get(CGM.VoidTy, ArgTypes, false);
+ llvm::Value *Fn = CGM.CreateRuntimeFunction(FnType,
+ ("__ubsan_handle_" + CheckName).str(),
+ llvm::Attribute::NoReturn |
+ llvm::Attribute::NoUnwind |
+ llvm::Attribute::UWTable);
+ llvm::CallInst *HandlerCall = Builder.CreateCall(Fn, Args);
+ HandlerCall->setDoesNotReturn();
+ HandlerCall->setDoesNotThrow();
+ Builder.CreateUnreachable();
+
EmitBlock(Cont);
}
@@ -2154,7 +2292,7 @@
if (E->isArrow()) {
llvm::Value *Ptr = EmitScalarExpr(BaseExpr);
QualType PtrTy = BaseExpr->getType()->getPointeeType();
- EmitTypeCheck(TCK_MemberAccess, Ptr, PtrTy);
+ EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Ptr, PtrTy);
BaseLV = MakeNaturalAlignAddrLValue(Ptr, PtrTy);
} else
BaseLV = EmitCheckedLValue(BaseExpr, TCK_MemberAccess);
@@ -2677,7 +2815,7 @@
}
RValue RV = EmitAnyExpr(E->getRHS());
- LValue LV = EmitLValue(E->getLHS());
+ LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store);
EmitStoreThroughLValue(RV, LV);
return LV;
}
Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=165536&r1=165535&r2=165536&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Tue Oct 9 14:52:38 2012
@@ -774,7 +774,7 @@
Visit(E->getRHS());
// Now emit the LHS and copy into it.
- LValue LHS = CGF.EmitLValue(E->getLHS());
+ LValue LHS = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
EmitCopy(E->getLHS()->getType(),
AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=165536&r1=165535&r2=165536&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Tue Oct 9 14:52:38 2012
@@ -24,6 +24,7 @@
using namespace CodeGen;
RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
+ SourceLocation CallLoc,
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
llvm::Value *This,
@@ -36,7 +37,7 @@
// C++11 [class.mfct.non-static]p2:
// If a non-static member function of a class X is called for an object that
// is not of type X, or of a type derived from X, the behavior is undefined.
- EmitTypeCheck(TCK_MemberCall, This,
+ EmitTypeCheck(TCK_MemberCall, CallLoc, This,
getContext().getRecordType(MD->getParent()));
CallArgList Args;
@@ -312,8 +313,8 @@
}
}
- return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
- CE->arg_begin(), CE->arg_end());
+ return EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
+ /*VTT=*/0, CE->arg_begin(), CE->arg_end());
}
RValue
@@ -343,7 +344,8 @@
else
This = EmitLValue(BaseExpr).getAddress();
- EmitTypeCheck(TCK_MemberCall, This, QualType(MPT->getClass(), 0));
+ EmitTypeCheck(TCK_MemberCall, E->getExprLoc(), This,
+ QualType(MPT->getClass(), 0));
// Ask the ABI to load the callee. Note that This is modified.
llvm::Value *Callee =
@@ -383,8 +385,8 @@
}
llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This);
- return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
- E->arg_begin() + 1, E->arg_end());
+ return EmitCXXMemberCall(MD, E->getExprLoc(), Callee, ReturnValue, This,
+ /*VTT=*/0, E->arg_begin() + 1, E->arg_end());
}
RValue CodeGenFunction::EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E,
@@ -1401,8 +1403,9 @@
= CGF.BuildVirtualCall(Dtor,
UseGlobalDelete? Dtor_Complete : Dtor_Deleting,
Ptr, Ty);
- CGF.EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, /*VTT=*/0,
- 0, 0);
+ // FIXME: Provide a source location here.
+ CGF.EmitCXXMemberCall(Dtor, SourceLocation(), Callee, ReturnValueSlot(),
+ Ptr, /*VTT=*/0, 0, 0);
if (UseGlobalDelete) {
CGF.PopCleanupBlock();
Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=165536&r1=165535&r2=165536&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Tue Oct 9 14:52:38 2012
@@ -85,6 +85,8 @@
return CGF.EmitCheckedLValue(E, TCK);
}
+ void EmitBinOpCheck(Value *Check, const BinOpInfo &Info);
+
Value *EmitLoadOfLValue(LValue LV) {
return CGF.EmitLoadOfLValue(LV).getScalarVal();
}
@@ -685,6 +687,54 @@
return llvm::Constant::getNullValue(ConvertType(Ty));
}
+/// \brief Emit a sanitization check for the given "binary" operation (which
+/// might actually be a unary increment which has been lowered to a binary
+/// operation). The check passes if \p Check, which is an \c i1, is \c true.
+void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
+ StringRef CheckName;
+ llvm::SmallVector<llvm::Constant *, 4> StaticData;
+ llvm::SmallVector<llvm::Value *, 2> DynamicData;
+
+ BinaryOperatorKind Opcode = Info.Opcode;
+ if (BinaryOperator::isCompoundAssignmentOp(Opcode))
+ Opcode = BinaryOperator::getOpForCompoundAssignment(Opcode);
+
+ StaticData.push_back(CGF.EmitCheckSourceLocation(Info.E->getExprLoc()));
+ const UnaryOperator *UO = dyn_cast<UnaryOperator>(Info.E);
+ if (UO && UO->getOpcode() == UO_Minus) {
+ CheckName = "negate_overflow";
+ StaticData.push_back(CGF.EmitCheckTypeDescriptor(UO->getType()));
+ DynamicData.push_back(Info.RHS);
+ } else {
+ if (BinaryOperator::isShiftOp(Opcode)) {
+ // Shift LHS negative or too large, or RHS out of bounds.
+ CheckName = "shift_out_of_bounds";
+ const BinaryOperator *BO = cast<BinaryOperator>(Info.E);
+ StaticData.push_back(
+ CGF.EmitCheckTypeDescriptor(BO->getLHS()->getType()));
+ StaticData.push_back(
+ CGF.EmitCheckTypeDescriptor(BO->getRHS()->getType()));
+ } else if (Opcode == BO_Div || Opcode == BO_Rem) {
+ // Divide or modulo by zero, or signed overflow (eg INT_MAX / -1).
+ CheckName = "divrem_overflow";
+ StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.E->getType()));
+ } else {
+ // Signed arithmetic overflow (+, -, *).
+ switch (Opcode) {
+ case BO_Add: CheckName = "add_overflow"; break;
+ case BO_Sub: CheckName = "sub_overflow"; break;
+ case BO_Mul: CheckName = "mul_overflow"; break;
+ default: llvm_unreachable("unexpected opcode for bin op check");
+ }
+ StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.E->getType()));
+ }
+ DynamicData.push_back(Info.LHS);
+ DynamicData.push_back(Info.RHS);
+ }
+
+ CGF.EmitCheck(Check, CheckName, StaticData, DynamicData);
+}
+
//===----------------------------------------------------------------------===//
// Visitor Methods
//===----------------------------------------------------------------------===//
@@ -1770,9 +1820,9 @@
llvm::Value *LHSCmp = Builder.CreateICmpNE(Ops.LHS, IntMin);
llvm::Value *RHSCmp = Builder.CreateICmpNE(Ops.RHS, NegOne);
llvm::Value *Cond2 = Builder.CreateOr(LHSCmp, RHSCmp, "or");
- CGF.EmitCheck(Builder.CreateAnd(Cond1, Cond2, "and"));
+ EmitBinOpCheck(Builder.CreateAnd(Cond1, Cond2, "and"), Ops);
} else {
- CGF.EmitCheck(Builder.CreateICmpNE(Ops.RHS, Zero));
+ EmitBinOpCheck(Builder.CreateICmpNE(Ops.RHS, Zero), Ops);
}
}
@@ -1783,7 +1833,7 @@
if (Ops.Ty->isIntegerType())
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
else if (Ops.Ty->isRealFloatingType())
- CGF.EmitCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero));
+ EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops);
}
if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
llvm::Value *Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
@@ -1856,7 +1906,7 @@
const std::string *handlerName =
&CGF.getContext().getLangOpts().OverflowHandler;
if (handlerName->empty()) {
- CGF.EmitCheck(Builder.CreateNot(overflow));
+ EmitBinOpCheck(Builder.CreateNot(overflow), Ops);
return result;
}
@@ -2185,7 +2235,9 @@
unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
llvm::Value *WidthMinusOne =
llvm::ConstantInt::get(RHS->getType(), Width - 1);
- CGF.EmitCheck(Builder.CreateICmpULE(RHS, WidthMinusOne));
+ // FIXME: Emit the branching explicitly rather than emitting the check
+ // twice.
+ EmitBinOpCheck(Builder.CreateICmpULE(RHS, WidthMinusOne), Ops);
if (Ops.Ty->hasSignedIntegerRepresentation()) {
// Check whether we are shifting any non-zero bits off the top of the
@@ -2204,7 +2256,7 @@
BitsShiftedOff = Builder.CreateLShr(BitsShiftedOff, One);
}
llvm::Value *Zero = llvm::ConstantInt::get(BitsShiftedOff->getType(), 0);
- CGF.EmitCheck(Builder.CreateICmpEQ(BitsShiftedOff, Zero));
+ EmitBinOpCheck(Builder.CreateICmpEQ(BitsShiftedOff, Zero), Ops);
}
}
@@ -2221,7 +2273,7 @@
if (CGF.CatchUndefined && isa<llvm::IntegerType>(Ops.LHS->getType())) {
unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
llvm::Value *WidthVal = llvm::ConstantInt::get(RHS->getType(), Width);
- CGF.EmitCheck(Builder.CreateICmpULT(RHS, WidthVal));
+ EmitBinOpCheck(Builder.CreateICmpULT(RHS, WidthVal), Ops);
}
if (Ops.Ty->hasUnsignedIntegerRepresentation())
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=165536&r1=165535&r2=165536&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Tue Oct 9 14:52:38 2012
@@ -544,7 +544,9 @@
if (getContext().getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() &&
!FD->getResultType()->isVoidType() && Builder.GetInsertBlock()) {
if (CatchUndefined)
- EmitCheck(Builder.getFalse());
+ EmitCheck(Builder.getFalse(), "missing_return",
+ EmitCheckSourceLocation(FD->getLocation()),
+ llvm::ArrayRef<llvm::Value*>());
Builder.CreateUnreachable();
Builder.ClearInsertionPoint();
}
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=165536&r1=165535&r2=165536&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Oct 9 14:52:38 2012
@@ -1503,7 +1503,7 @@
static bool hasAggregateLLVMType(QualType T);
/// createBasicBlock - Create an LLVM basic block.
- llvm::BasicBlock *createBasicBlock(StringRef name = "",
+ llvm::BasicBlock *createBasicBlock(const Twine &name = "",
llvm::Function *parent = 0,
llvm::BasicBlock *before = 0) {
#ifdef NDEBUG
@@ -1867,7 +1867,7 @@
/// \brief Emit a check that \p V is the address of storage of the
/// appropriate size and alignment for an object of type \p Type.
- void EmitTypeCheck(TypeCheckKind TCK, llvm::Value *V,
+ void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, llvm::Value *V,
QualType Type, CharUnits Alignment = CharUnits::Zero());
llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
@@ -2262,6 +2262,7 @@
const CXXRecordDecl *RD);
RValue EmitCXXMemberCall(const CXXMethodDecl *MD,
+ SourceLocation CallLoc,
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
llvm::Value *This,
@@ -2548,9 +2549,23 @@
void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock,
llvm::BasicBlock *FalseBlock);
+ /// \brief Emit a description of a type in a format suitable for passing to
+ /// a runtime sanitizer handler.
+ llvm::Constant *EmitCheckTypeDescriptor(QualType T);
+
+ /// \brief Convert a value into a format suitable for passing to a runtime
+ /// sanitizer handler.
+ llvm::Value *EmitCheckValue(llvm::Value *V);
+
+ /// \brief Emit a description of a source location in a format suitable for
+ /// passing to a runtime sanitizer handler.
+ llvm::Constant *EmitCheckSourceLocation(SourceLocation Loc);
+
/// \brief Create a basic block that will call the trap intrinsic, and emit a
/// conditional branch to it.
- void EmitCheck(llvm::Value *Checked);
+ void EmitCheck(llvm::Value *Checked, StringRef CheckName,
+ llvm::ArrayRef<llvm::Constant *> StaticArgs,
+ llvm::ArrayRef<llvm::Value *> DynamicArgs);
/// EmitCallArg - Emit a single call argument.
void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType);
Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=165536&r1=165535&r2=165536&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Tue Oct 9 14:52:38 2012
@@ -1466,6 +1466,23 @@
}
}
+/// If UndefinedBehaviorSanitizer is enabled, add appropriate linker flags
+/// (Linux).
+static void addUbsanRTLinux(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ if (!Args.hasArg(options::OPT_fcatch_undefined_behavior))
+ return;
+ if (!Args.hasArg(options::OPT_shared)) {
+ // LibUbsan is "libclang_rt.ubsan-<ArchName>.a" in the Linux library
+ // resource directory.
+ SmallString<128> LibUbsan(TC.getDriver().ResourceDir);
+ llvm::sys::path::append(LibUbsan, "lib", "linux",
+ (Twine("libclang_rt.ubsan-") +
+ TC.getArchName() + ".a"));
+ CmdArgs.push_back(Args.MakeArgString(LibUbsan));
+ }
+}
+
static bool shouldUseFramePointer(const ArgList &Args,
const llvm::Triple &Triple) {
if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer,
@@ -5911,6 +5928,7 @@
}
addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
+ addUbsanRTLinux(getToolChain(), Args, CmdArgs);
C.addCommand(new Command(JA, *this, ToolChain.Linker.c_str(), CmdArgs));
}
Modified: cfe/trunk/test/CodeGen/catch-undef-behavior.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/catch-undef-behavior.c?rev=165536&r1=165535&r2=165536&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/catch-undef-behavior.c (original)
+++ cfe/trunk/test/CodeGen/catch-undef-behavior.c Tue Oct 9 14:52:38 2012
@@ -1,50 +1,130 @@
// RUN: %clang_cc1 -fcatch-undefined-behavior -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+// CHECK: @[[INT_STR:.*]] = private unnamed_addr constant [6 x i8] c"'int'\00"
+// CHECK: @[[INT:.*]] = private unnamed_addr constant { i8*, i16, i16 } { i8* getelementptr inbounds ([6 x i8]* @[[INT_STR]], i32 0, i32 0), i16 0, i16 11 }
+
+// FIXME: When we only emit each type once, use [[INT]] more below.
+// CHECK: @[[LINE_100:.*]] = private unnamed_addr constant {{.*}}, i32 100, i32 5 {{.*}} @[[INT]], i64 4, i8 1
+// CHECK: @[[LINE_200:.*]] = {{.*}}, i32 200, i32 10 {{.*}}, i64 4, i8 0
+// CHECK: @[[LINE_300_A:.*]] = {{.*}}, i32 300, i32 12 {{.*}} @{{.*}}, {{.*}} @{{.*}}
+// CHECK: @[[LINE_300_B:.*]] = {{.*}}, i32 300, i32 12 {{.*}} @{{.*}}, {{.*}} @{{.*}}
+// CHECK: @[[LINE_400:.*]] = {{.*}}, i32 400, i32 12 {{.*}} @{{.*}}, {{.*}} @{{.*}}
+// CHECK: @[[LINE_500:.*]] = {{.*}}, i32 500, i32 10 {{.*}} @{{.*}}, i64 4, i8 0 }
+// CHECK: @[[LINE_600:.*]] = {{.*}}, i32 600, i32 3 {{.*}} @{{.*}}, i64 4, i8 1 }
+
+// CHECK: @[[STRUCT_S_STR:.*]] = private unnamed_addr constant [11 x i8] c"'struct S'\00"
+// CHECK: @[[STRUCT_S:.*]] = private unnamed_addr constant {{.*}}@[[STRUCT_S_STR]], i32 0, i32 0), i16 -1, i16 0 }
+
+// CHECK: @[[LINE_700:.*]] = {{.*}}, i32 700, i32 14 {{.*}} @[[STRUCT_S]], i64 4, i8 3 }
+// CHECK: @[[LINE_800:.*]] = {{.*}}, i32 800, i32 12 {{.*}} @{{.*}} }
+
// PR6805
// CHECK: @foo
void foo() {
union { int i; } u;
- // CHECK: objectsize
- // CHECK: icmp uge
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64({{.*}} %[[PTR:.*]], i1 false)
+ // CHECK-NEXT: %[[CHECK1:.*]] = icmp uge i64 %[[SIZE]], 4
+
+ // CHECK: %[[PTRTOINT:.*]] = ptrtoint {{.*}} %[[PTR]] to i64
+ // CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRTOINT]], 3
+ // CHECK-NEXT: %[[CHECK2:.*]] = icmp eq i64 %[[MISALIGN]], 0
+
+ // CHECK: %[[OK:.*]] = and i1 %[[CHECK1]], %[[CHECK2]]
+ // CHECK-NEXT: br i1 %[[OK]]
+
+ // CHECK: %[[ARG:.*]] = ptrtoint {{.*}} %[[PTR]] to i64
+ // CHECK-NEXT: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_100]] to i8*), i64 %[[ARG]]) noreturn nounwind
+#line 100
u.i=1;
}
// CHECK: @bar
int bar(int *a) {
- // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
// CHECK-NEXT: icmp uge i64 %[[SIZE]], 4
- // CHECK: %[[PTRINT:.*]] = ptrtoint
+ // CHECK: %[[PTRINT:.*]] = ptrtoint
// CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 3
// CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
+
+ // CHECK: %[[ARG:.*]] = ptrtoint
+ // CHECK-NEXT: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_200]] to i8*), i64 %[[ARG]]) noreturn nounwind
+#line 200
return *a;
}
// CHECK: @lsh_overflow
int lsh_overflow(int a, int b) {
- // CHECK: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
+ // CHECK: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
// CHECK-NEXT: br i1 %[[INBOUNDS]]
- // CHECK: %[[SHIFTED_OUT_WIDTH:.*]] = sub nuw nsw i32 31, %[[RHS]]
+ // FIXME: Only emit one trap block here.
+ // CHECK: %[[ARG1:.*]] = zext
+ // CHECK-NEXT: %[[ARG2:.*]] = zext
+ // CHECK-NEXT: call void @__ubsan_handle_shift_out_of_bounds(i8* bitcast ({{.*}} @[[LINE_300_A]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]]) noreturn nounwind
+
+ // CHECK: %[[SHIFTED_OUT_WIDTH:.*]] = sub nuw nsw i32 31, %[[RHS]]
// CHECK-NEXT: %[[SHIFTED_OUT:.*]] = lshr i32 %[[LHS:.*]], %[[SHIFTED_OUT_WIDTH]]
// CHECK-NEXT: %[[NO_OVERFLOW:.*]] = icmp eq i32 %[[SHIFTED_OUT]], 0
// CHECK-NEXT: br i1 %[[NO_OVERFLOW]]
- // CHECK: %[[RET:.*]] = shl i32 %[[LHS]], %[[RHS]]
+ // CHECK: %[[ARG1:.*]] = zext
+ // CHECK-NEXT: %[[ARG2:.*]] = zext
+ // CHECK-NEXT: call void @__ubsan_handle_shift_out_of_bounds(i8* bitcast ({{.*}} @[[LINE_300_B]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]]) noreturn nounwind
+
+ // CHECK: %[[RET:.*]] = shl i32 %[[LHS]], %[[RHS]]
// CHECK-NEXT: ret i32 %[[RET]]
+#line 300
return a << b;
}
// CHECK: @rsh_inbounds
int rsh_inbounds(int a, int b) {
- // CHECK: %[[INBOUNDS:.*]] = icmp ult i32 %[[RHS:.*]], 32
- // CHECK: br i1 %[[INBOUNDS]]
+ // CHECK: %[[INBOUNDS:.*]] = icmp ult i32 %[[RHS:.*]], 32
+ // CHECK: br i1 %[[INBOUNDS]]
+
+ // CHECK: %[[ARG1:.*]] = zext
+ // CHECK-NEXT: %[[ARG2:.*]] = zext
+ // CHECK-NEXT: call void @__ubsan_handle_shift_out_of_bounds(i8* bitcast ({{.*}} @[[LINE_400]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]]) noreturn nounwind
- // CHECK: %[[RET:.*]] = ashr i32 %[[LHS]], %[[RHS]]
+ // CHECK: %[[RET:.*]] = ashr i32 %[[LHS]], %[[RHS]]
// CHECK-NEXT: ret i32 %[[RET]]
+#line 400
return a >> b;
}
+// CHECK: @load
+int load(int *p) {
+ // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_500]] to i8*), i64 %{{.*}}) noreturn nounwind
+#line 500
+ return *p;
+}
+
+// CHECK: @store
+void store(int *p, int q) {
+ // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_600]] to i8*), i64 %{{.*}}) noreturn nounwind
+#line 600
+ *p = q;
+}
+
+struct S { int k; };
+
+// CHECK: @member_access
+int *member_access(struct S *p) {
+ // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_700]] to i8*), i64 %{{.*}}) noreturn nounwind
+#line 700
+ return &p->k;
+}
+
+// CHECK: @signed_overflow
+int signed_overflow(int a, int b) {
+ // CHECK: %[[ARG1:.*]] = zext
+ // CHECK-NEXT: %[[ARG2:.*]] = zext
+ // CHECK-NEXT: call void @__ubsan_handle_add_overflow(i8* bitcast ({{.*}} @[[LINE_800]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]]) noreturn nounwind
+#line 800
+ return a + b;
+}
+
// CHECK: @no_return
int no_return() {
// Reaching the end of a noreturn function is fine in C.
Modified: cfe/trunk/test/CodeGen/trapv.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/trapv.c?rev=165536&r1=165535&r2=165536&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/trapv.c (original)
+++ cfe/trunk/test/CodeGen/trapv.c Tue Oct 9 14:52:38 2012
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -ftrapv %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fcatch-undefined-behavior %s -emit-llvm -o - | FileCheck %s
unsigned int ui, uj, uk;
int i, j, k;
Modified: cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp?rev=165536&r1=165535&r2=165536&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp Tue Oct 9 14:52:38 2012
@@ -89,6 +89,6 @@
// CHECK: @_Z9no_return
int no_return() {
- // CHECK: call void @llvm.trap
- // CHECK: unreachable
+ // CHECK: call void @__ubsan_handle_missing_return(i8* bitcast ({{.*}}* @{{.*}} to i8*)) noreturn nounwind
+ // CHECK-NEXT: unreachable
}
More information about the cfe-commits
mailing list