diff options
-rw-r--r-- | include/clang/Basic/Diagnostic.h | 2 | ||||
-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 | ||||
-rw-r--r-- | lib/Driver/Tools.cpp | 18 | ||||
-rw-r--r-- | test/CodeGen/catch-undef-behavior.c | 100 | ||||
-rw-r--r-- | test/CodeGen/trapv.c | 1 | ||||
-rw-r--r-- | test/CodeGenCXX/catch-undef-behavior.cpp | 4 |
13 files changed, 376 insertions, 63 deletions
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index b596937061..ef9c3cb4e5 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -587,7 +587,7 @@ public: 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); 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); diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 468a362b3c..790b9f0299 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -1466,6 +1466,23 @@ static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args, } } +/// 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 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, } addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple()); + addUbsanRTLinux(getToolChain(), Args, CmdArgs); C.addCommand(new Command(JA, *this, ToolChain.Linker.c_str(), CmdArgs)); } diff --git a/test/CodeGen/catch-undef-behavior.c b/test/CodeGen/catch-undef-behavior.c index 53dda5c8b2..5e72889e9e 100644 --- a/test/CodeGen/catch-undef-behavior.c +++ b/test/CodeGen/catch-undef-behavior.c @@ -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: %[[RET:.*]] = ashr i32 %[[LHS]], %[[RHS]] + // 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-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. diff --git a/test/CodeGen/trapv.c b/test/CodeGen/trapv.c index dd50d5cb0a..a259ebddae 100644 --- a/test/CodeGen/trapv.c +++ b/test/CodeGen/trapv.c @@ -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; diff --git a/test/CodeGenCXX/catch-undef-behavior.cpp b/test/CodeGenCXX/catch-undef-behavior.cpp index fdc2b00bcb..bfe716847e 100644 --- a/test/CodeGenCXX/catch-undef-behavior.cpp +++ b/test/CodeGenCXX/catch-undef-behavior.cpp @@ -89,6 +89,6 @@ int lsh_overflow(int a, int b) { // 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 } |