aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGExpr.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-08-24 00:54:33 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-08-24 00:54:33 +0000
commit2c9f87ca5cccbfdaad82762368af5b2323320653 (patch)
treee22ac59c06b9a9e7149788fba3e590fea2ce1aab /lib/CodeGen/CGExpr.cpp
parent6fbe982bb487931feb3f1ceb9eec8f7f1961393a (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.cpp83
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)) {