diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-10-09 19:52:38 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-10-09 19:52:38 +0000 |
commit | 4def70d3040e73707c738f7c366737a986135edf (patch) | |
tree | 0699902c58619f54157b8802bd8d25909da63385 /lib/CodeGen | |
parent | d372a70c6845efcfc88edc37341f795fc70750c7 (diff) |
-fcatch-undefined-behavior: emit calls to the runtime library whenever one of the checks fails.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165536 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGBuiltin.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 8 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 190 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGExprCXX.cpp | 19 | ||||
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 66 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 21 |
8 files changed, 265 insertions, 49 deletions
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 3a45913d3f..cf124caec1 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -409,7 +409,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, } 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(); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index e37fa3ab72..84c43b8881 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -1268,7 +1268,9 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, 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 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, 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 { diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index fac6e37002..3f15692e03 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -493,7 +493,7 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E, // 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 @@ unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx, ->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 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, llvm::Value *Address, 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 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, llvm::Value *Address, 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 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, llvm::Value *Address, 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::EmitUnsupportedLValue(const Expr *E, 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 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { } } -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::BasicBlock *Cont = createBasicBlock("cont"); + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), Descriptor->getType(), + /*isConstant=*/true, + llvm::GlobalVariable::PrivateLinkage, + Descriptor); + GV->setUnnamedAddr(true); + return GV; +} - // 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; +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()) + }; - if (NeedNewTrapBB) - TrapBB = createBasicBlock("trap"); + return llvm::ConstantStruct::getAnon(Data); +} - Builder.CreateCondBr(Checked, Cont, TrapBB); +void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName, + llvm::ArrayRef<llvm::Constant *> StaticArgs, + llvm::ArrayRef<llvm::Value *> DynamicArgs) { + llvm::BasicBlock *Cont = createBasicBlock("cont"); - if (NeedNewTrapBB) { - EmitBlock(TrapBB); + // 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); + } - llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap); - llvm::CallInst *TrapCall = Builder.CreateCall(F); - TrapCall->setDoesNotReturn(); - TrapCall->setDoesNotThrow(); - Builder.CreateUnreachable(); + 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 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { 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 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { } RValue RV = EmitAnyExpr(E->getRHS()); - LValue LV = EmitLValue(E->getLHS()); + LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store); EmitStoreThroughLValue(RV, LV); return LV; } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 200b43aa6d..218100247b 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -774,7 +774,7 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { 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, diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 16311963b3..631923002e 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -24,6 +24,7 @@ using namespace clang; using namespace CodeGen; RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, + SourceLocation CallLoc, llvm::Value *Callee, ReturnValueSlot ReturnValue, llvm::Value *This, @@ -36,7 +37,7 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, // 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 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, } } - 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 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, 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 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, } 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 @@ static void EmitObjectDelete(CodeGenFunction &CGF, = 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(); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 17454c104c..cd42585f9e 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -85,6 +85,8 @@ public: 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 @@ Value *ScalarExprEmitter::EmitNullValue(QualType Ty) { 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 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( 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 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { 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 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { 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 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) { 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 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) { 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 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { 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()) diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index a86c2e4fa1..d7fcf9f8b2 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -544,7 +544,9 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, 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(); } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 4a0c35bd82..11ee36ba0c 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1503,7 +1503,7 @@ public: 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 @@ public: /// \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 @@ public: const CXXRecordDecl *RD); RValue EmitCXXMemberCall(const CXXMethodDecl *MD, + SourceLocation CallLoc, llvm::Value *Callee, ReturnValueSlot ReturnValue, llvm::Value *This, @@ -2548,9 +2549,23 @@ public: 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); |