diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-08-24 00:54:33 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-08-24 00:54:33 +0000 |
| commit | 2c9f87ca5cccbfdaad82762368af5b2323320653 (patch) | |
| tree | e22ac59c06b9a9e7149788fba3e590fea2ce1aab /lib/CodeGen/CGExpr.cpp | |
| parent | 6fbe982bb487931feb3f1ceb9eec8f7f1961393a (diff) | |
New -fcatch-undefined-behavior features:
* when checking that a pointer or reference refers to appropriate storage for a type, also check the alignment and perform a null check
* check that references are bound to appropriate storage
* check that 'this' has appropriate storage in member accesses and member function calls
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162523 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGExpr.cpp')
| -rw-r--r-- | lib/CodeGen/CGExpr.cpp | 83 |
1 files changed, 62 insertions, 21 deletions
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 1fe4c18bad..e7dbe791c9 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -486,6 +486,15 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E, ReferenceTemporaryDtor, ObjCARCReferenceLifetimeType, InitializedDecl); + if (CatchUndefined && !E->getType()->isFunctionType()) { + // C++11 [dcl.ref]p5 (as amended by core issue 453): + // If a glvalue to which a reference is directly bound designates neither + // an existing object or function of an appropriate type nor a region of + // storage of suitable size and alignment to contain an object of the + // reference's type, the behavior is undefined. + QualType Ty = E->getType(); + EmitCheck(CT_ReferenceBinding, Value, Ty); + } if (!ReferenceTemporaryDtor && ObjCARCReferenceLifetimeType.isNull()) return RValue::get(Value); @@ -549,22 +558,53 @@ unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx, ->getZExtValue(); } -void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) { +void CodeGenFunction::EmitCheck(CheckType CT, llvm::Value *Address, QualType Ty, + CharUnits Alignment) { if (!CatchUndefined) return; - // This needs to be to the standard address space. - Address = Builder.CreateBitCast(Address, Int8PtrTy); - - llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, IntPtrTy); - - llvm::Value *Min = Builder.getFalse(); - llvm::Value *C = Builder.CreateCall2(F, Address, Min); - llvm::BasicBlock *Cont = createBasicBlock(); - Builder.CreateCondBr(Builder.CreateICmpUGE(C, - llvm::ConstantInt::get(IntPtrTy, Size)), - Cont, getTrapBB()); - EmitBlock(Cont); + llvm::Value *Cond = 0; + + if (CT != CT_Load && CT != CT_Store) { + // The glvalue must not be an empty glvalue. Don't bother checking this for + // loads and stores, because we will get a segfault anyway (if the operation + // isn't optimized out). + Cond = Builder.CreateICmpNE( + Address, llvm::Constant::getNullValue(Address->getType())); + } + + if (!Ty->isIncompleteType()) { + uint64_t Size = getContext().getTypeSizeInChars(Ty).getQuantity(); + uint64_t AlignVal = Alignment.getQuantity(); + if (!AlignVal) + AlignVal = getContext().getTypeAlignInChars(Ty).getQuantity(); + + // This needs to be to the standard address space. + Address = Builder.CreateBitCast(Address, Int8PtrTy); + + // The glvalue must refer to a large enough storage region. + // FIXME: If -faddress-sanitizer is enabled, insert dynamic instrumentation + // to check this. + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, IntPtrTy); + llvm::Value *Min = Builder.getFalse(); + llvm::Value *LargeEnough = + Builder.CreateICmpUGE(Builder.CreateCall2(F, Address, Min), + llvm::ConstantInt::get(IntPtrTy, Size)); + Cond = Cond ? Builder.CreateAnd(Cond, LargeEnough) : LargeEnough; + + // The glvalue must be suitably aligned. + llvm::Value *Align = + Builder.CreateAnd(Builder.CreatePtrToInt(Address, IntPtrTy), + llvm::ConstantInt::get(IntPtrTy, AlignVal - 1)); + Cond = Builder.CreateAnd(Cond, + Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0))); + } + + if (Cond) { + llvm::BasicBlock *Cont = createBasicBlock(); + Builder.CreateCondBr(Cond, Cont, getTrapBB()); + EmitBlock(Cont); + } } @@ -641,11 +681,10 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E, return MakeAddrLValue(llvm::UndefValue::get(Ty), E->getType()); } -LValue CodeGenFunction::EmitCheckedLValue(const Expr *E) { +LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, CheckType CT) { LValue LV = EmitLValue(E); if (!isa<DeclRefExpr>(E) && !LV.isBitField() && LV.isSimple()) - EmitCheck(LV.getAddress(), - getContext().getTypeSizeInChars(E->getType()).getQuantity()); + EmitCheck(CT, LV.getAddress(), E->getType(), LV.getAlignment()); return LV; } @@ -2114,11 +2153,13 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar. LValue BaseLV; - if (E->isArrow()) - BaseLV = MakeNaturalAlignAddrLValue(EmitScalarExpr(BaseExpr), - BaseExpr->getType()->getPointeeType()); - else - BaseLV = EmitLValue(BaseExpr); + if (E->isArrow()) { + llvm::Value *Ptr = EmitScalarExpr(BaseExpr); + QualType PtrTy = BaseExpr->getType()->getPointeeType(); + EmitCheck(CT_MemberAccess, Ptr, PtrTy); + BaseLV = MakeNaturalAlignAddrLValue(Ptr, PtrTy); + } else + BaseLV = EmitCheckedLValue(BaseExpr, CT_MemberAccess); NamedDecl *ND = E->getMemberDecl(); if (FieldDecl *Field = dyn_cast<FieldDecl>(ND)) { |
