[cfe-commits] r162523 - in /cfe/trunk: lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprCXX.cpp lib/CodeGen/CGExprScalar.cpp lib/CodeGen/CodeGenFunction.h test/CodeGen/catch-undef-behavior.c test/CodeGenCXX/catch-undef-behavior.cpp
Richard Smith
richard-llvm at metafoo.co.uk
Thu Aug 23 17:54:33 PDT 2012
Author: rsmith
Date: Thu Aug 23 19:54:33 2012
New Revision: 162523
URL: http://llvm.org/viewvc/llvm-project?rev=162523&view=rev
Log:
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
Added:
cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp
Modified:
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.h
cfe/trunk/test/CodeGen/catch-undef-behavior.c
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=162523&r1=162522&r2=162523&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Thu Aug 23 19:54:33 2012
@@ -486,6 +486,15 @@
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 @@
->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 *Cond = 0;
- 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);
+ 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 @@
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 @@
// 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)) {
Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=162523&r1=162522&r2=162523&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Thu Aug 23 19:54:33 2012
@@ -549,8 +549,10 @@
void AggExprEmitter::VisitCastExpr(CastExpr *E) {
switch (E->getCastKind()) {
case CK_Dynamic: {
+ // FIXME: Can this actually happen? We have no test coverage for it.
assert(isa<CXXDynamicCastExpr>(E) && "CK_Dynamic without a dynamic_cast?");
- LValue LV = CGF.EmitCheckedLValue(E->getSubExpr());
+ LValue LV = CGF.EmitCheckedLValue(E->getSubExpr(),
+ CodeGenFunction::CT_Load);
// FIXME: Do we also need to handle property references here?
if (LV.isSimple())
CGF.EmitDynamicCast(LV.getAddress(), cast<CXXDynamicCastExpr>(E));
Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=162523&r1=162522&r2=162523&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Thu Aug 23 19:54:33 2012
@@ -33,6 +33,11 @@
assert(MD->isInstance() &&
"Trying to emit a member call expr on a static method!");
+ // 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.
+ EmitCheck(CT_MemberCall, This, getContext().getRecordType(MD->getParent()));
+
CallArgList Args;
// Push the this ptr.
@@ -337,6 +342,8 @@
else
This = EmitLValue(BaseExpr).getAddress();
+ EmitCheck(CT_MemberCall, This, QualType(MPT->getClass(), 0));
+
// Ask the ABI to load the callee. Note that This is modified.
llvm::Value *Callee =
CGM.getCXXABI().EmitLoadOfMemberFunctionPointer(*this, This, MemFnPtr, MPT);
Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=162523&r1=162522&r2=162523&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Thu Aug 23 19:54:33 2012
@@ -80,7 +80,9 @@
llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); }
LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); }
- LValue EmitCheckedLValue(const Expr *E) { return CGF.EmitCheckedLValue(E); }
+ LValue EmitCheckedLValue(const Expr *E, CodeGenFunction::CheckType CT) {
+ return CGF.EmitCheckedLValue(E, CT);
+ }
Value *EmitLoadOfLValue(LValue LV) {
return CGF.EmitLoadOfLValue(LV).getScalarVal();
@@ -90,7 +92,7 @@
/// value l-value, this method emits the address of the l-value, then loads
/// and returns the result.
Value *EmitLoadOfLValue(const Expr *E) {
- return EmitLoadOfLValue(EmitCheckedLValue(E));
+ return EmitLoadOfLValue(EmitCheckedLValue(E, CodeGenFunction::CT_Load));
}
/// EmitConversionToBool - Convert the specified expression value to a
@@ -1680,7 +1682,7 @@
OpInfo.Opcode = E->getOpcode();
OpInfo.E = E;
// Load/convert the LHS.
- LValue LHSLV = EmitCheckedLValue(E->getLHS());
+ LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::CT_Store);
OpInfo.LHS = EmitLoadOfLValue(LHSLV);
llvm::PHINode *atomicPHI = 0;
@@ -2326,7 +2328,7 @@
case Qualifiers::OCL_Weak:
RHS = Visit(E->getRHS());
- LHS = EmitCheckedLValue(E->getLHS());
+ LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::CT_Store);
RHS = CGF.EmitARCStoreWeak(LHS.getAddress(), RHS, Ignore);
break;
@@ -2336,7 +2338,7 @@
// __block variables need to have the rhs evaluated first, plus
// this should improve codegen just a little.
RHS = Visit(E->getRHS());
- LHS = EmitCheckedLValue(E->getLHS());
+ LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::CT_Store);
// Store the value into the LHS. Bit-fields are handled specially
// because the result is altered by the store, i.e., [C99 6.5.16p1]
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=162523&r1=162522&r2=162523&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Thu Aug 23 19:54:33 2012
@@ -1833,7 +1833,29 @@
void EmitStdInitializerListCleanup(llvm::Value *loc,
const InitListExpr *init);
- void EmitCheck(llvm::Value *, unsigned Size);
+ /// \brief Situations in which we might emit a check for the suitability of a
+ /// pointer or glvalue.
+ enum CheckType {
+ /// Checking the operand of a load. Must be suitably sized and aligned.
+ CT_Load,
+ /// Checking the destination of a store. Must be suitably sized and aligned.
+ CT_Store,
+ /// Checking the bound value in a reference binding. Must be suitably sized
+ /// and aligned, but is not required to refer to an object (until the
+ /// reference is used), per core issue 453.
+ CT_ReferenceBinding,
+ /// Checking the object expression in a non-static data member access. Must
+ /// be an object within its lifetime.
+ CT_MemberAccess,
+ /// Checking the 'this' pointer for a call to a non-static member function.
+ /// Must be an object within its lifetime.
+ CT_MemberCall
+ };
+
+ /// EmitCheck - 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 EmitCheck(CheckType CT, llvm::Value *V,
+ QualType Type, CharUnits Alignment = CharUnits::Zero());
llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre);
@@ -2036,7 +2058,7 @@
/// checking code to guard against undefined behavior. This is only
/// suitable when we know that the address will be used to access the
/// object.
- LValue EmitCheckedLValue(const Expr *E);
+ LValue EmitCheckedLValue(const Expr *E, CheckType CT);
/// EmitToMemory - Change a scalar value from its value
/// representation to its in-memory representation.
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=162523&r1=162522&r2=162523&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/catch-undef-behavior.c (original)
+++ cfe/trunk/test/CodeGen/catch-undef-behavior.c Thu Aug 23 19:54:33 2012
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcatch-undefined-behavior -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fcatch-undefined-behavior -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
// PR6805
// CHECK: @foo
@@ -11,7 +11,11 @@
// CHECK: @bar
int bar(int *a) {
- // CHECK: objectsize
- // CHECK: icmp uge
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
+ // CHECK-NEXT: icmp uge i64 %[[SIZE]], 4
+
+ // CHECK: %[[PTRINT:.*]] = ptrtoint
+ // CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 3
+ // CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
return *a;
}
Added: cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp?rev=162523&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp Thu Aug 23 19:54:33 2012
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -fcatch-undefined-behavior -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+
+// CHECK: @_Z17reference_binding
+void reference_binding(int *p) {
+ // C++ core issue 453: If an lvalue 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.
+
+ // CHECK: icmp ne {{.*}}, null
+
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
+ // CHECK-NEXT: icmp uge i64 %[[SIZE]], 4
+
+ // CHECK: %[[PTRINT:.*]] = ptrtoint
+ // CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 3
+ // CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
+ int &r = *p;
+}
+
+struct S {
+ double d;
+ int a, b;
+ virtual int f();
+};
+
+// CHECK: @_Z13member_access
+void member_access(S *p) {
+ // (1) Check 'p' is appropriately sized and aligned for member access.
+
+ // FIXME: Check vptr is for 'S' or a class derived from 'S'.
+
+ // CHECK: icmp ne {{.*}}, null
+
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
+ // CHECK-NEXT: icmp uge i64 %[[SIZE]], 24
+
+ // CHECK: %[[PTRINT:.*]] = ptrtoint
+ // CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 7
+ // CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
+
+ // (2) Check 'p->b' is appropriately sized and aligned for a load.
+
+ // FIXME: Suppress this in the trivial case of a member access, because we
+ // know we've just checked the member access expression itself.
+
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
+ // CHECK-NEXT: icmp uge i64 %[[SIZE]], 4
+
+ // CHECK: %[[PTRINT:.*]] = ptrtoint
+ // CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 3
+ // CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
+ int k = p->b;
+
+ // (3) Check 'p' is appropriately sized and aligned for member function call.
+
+ // FIXME: Check vptr is for 'S' or a class derived from 'S'.
+
+ // CHECK: icmp ne {{.*}}, null
+
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
+ // CHECK-NEXT: icmp uge i64 %[[SIZE]], 24
+
+ // CHECK: %[[PTRINT:.*]] = ptrtoint
+ // CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 7
+ // CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
+ k = p->f();
+}
More information about the cfe-commits
mailing list