r175078 - ubsan: Add checking for invalid downcasts. Per [expr.static.cast]p2 and p11,
Richard Smith
richard-llvm at metafoo.co.uk
Wed Feb 13 13:18:24 PST 2013
Author: rsmith
Date: Wed Feb 13 15:18:23 2013
New Revision: 175078
URL: http://llvm.org/viewvc/llvm-project?rev=175078&view=rev
Log:
ubsan: Add checking for invalid downcasts. Per [expr.static.cast]p2 and p11,
base-to-derived casts have undefined behavior if the object is not actually an
instance of the derived type.
Modified:
cfe/trunk/lib/CodeGen/CGClass.cpp
cfe/trunk/lib/CodeGen/CGExpr.cpp
cfe/trunk/lib/CodeGen/CGExprScalar.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp
Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=175078&r1=175077&r2=175078&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Wed Feb 13 15:18:23 2013
@@ -232,7 +232,7 @@ CodeGenFunction::GetAddressOfDerivedClas
QualType DerivedTy =
getContext().getCanonicalType(getContext().getTagDeclType(Derived));
llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
-
+
llvm::Value *NonVirtualOffset =
CGM.GetNonVirtualBaseClassOffset(Derived, PathBegin, PathEnd);
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=175078&r1=175077&r2=175078&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Wed Feb 13 15:18:23 2013
@@ -501,11 +501,22 @@ void CodeGenFunction::EmitTypeCheck(Type
return;
llvm::Value *Cond = 0;
+ llvm::BasicBlock *Done = 0;
if (SanOpts->Null) {
// The glvalue must not be an empty glvalue.
Cond = Builder.CreateICmpNE(
Address, llvm::Constant::getNullValue(Address->getType()));
+
+ if (TCK == TCK_DowncastPointer) {
+ // When performing a pointer downcast, it's OK if the value is null.
+ // Skip the remaining checks in that case.
+ Done = createBasicBlock("null");
+ llvm::BasicBlock *Rest = createBasicBlock("not.null");
+ Builder.CreateCondBr(Cond, Rest, Done);
+ EmitBlock(Rest);
+ Cond = 0;
+ }
}
if (SanOpts->ObjectSize && !Ty->isIncompleteType()) {
@@ -561,7 +572,8 @@ void CodeGenFunction::EmitTypeCheck(Type
// or call a non-static member function
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
if (SanOpts->Vptr &&
- (TCK == TCK_MemberAccess || TCK == TCK_MemberCall) &&
+ (TCK == TCK_MemberAccess || TCK == TCK_MemberCall ||
+ TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference) &&
RD && RD->hasDefinition() && RD->isDynamicClass()) {
// Compute a hash of the mangled name of the type.
//
@@ -611,6 +623,11 @@ void CodeGenFunction::EmitTypeCheck(Type
"dynamic_type_cache_miss", StaticData, DynamicData,
CRK_AlwaysRecoverable);
}
+
+ if (Done) {
+ Builder.CreateBr(Done);
+ EmitBlock(Done);
+ }
}
@@ -2638,7 +2655,13 @@ LValue CodeGenFunction::EmitCastLValue(c
cast<CXXRecordDecl>(DerivedClassTy->getDecl());
LValue LV = EmitLValue(E->getSubExpr());
-
+
+ // C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is
+ // performed and the object is not of the derived type.
+ if (SanitizePerformTypeCheck)
+ EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(),
+ LV.getAddress(), E->getType());
+
// Perform the base-to-derived conversion
llvm::Value *Derived =
GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl,
Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=175078&r1=175077&r2=175078&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Wed Feb 13 15:18:23 2013
@@ -1220,7 +1220,15 @@ Value *ScalarExprEmitter::VisitCastExpr(
const CXXRecordDecl *DerivedClassDecl = DestTy->getPointeeCXXRecordDecl();
assert(DerivedClassDecl && "BaseToDerived arg isn't a C++ object pointer!");
- return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl,
+ llvm::Value *V = Visit(E);
+
+ // C++11 [expr.static.cast]p11: Behavior is undefined if a downcast is
+ // performed and the object is not of the derived type.
+ if (CGF.SanitizePerformTypeCheck)
+ CGF.EmitTypeCheck(CodeGenFunction::TCK_DowncastPointer, CE->getExprLoc(),
+ V, DestTy->getPointeeType());
+
+ return CGF.GetAddressOfDerivedClass(V, DerivedClassDecl,
CE->path_begin(), CE->path_end(),
ShouldNullCheckClassCastValue(CE));
}
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=175078&r1=175077&r2=175078&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Feb 13 15:18:23 2013
@@ -1895,7 +1895,13 @@ public:
/// Must be an object within its lifetime.
TCK_MemberCall,
/// Checking the 'this' pointer for a constructor call.
- TCK_ConstructorCall
+ TCK_ConstructorCall,
+ /// Checking the operand of a static_cast to a derived pointer type. Must be
+ /// null or an object within its lifetime.
+ TCK_DowncastPointer,
+ /// Checking the operand of a static_cast to a derived reference type. Must
+ /// be an object within its lifetime.
+ TCK_DowncastReference
};
/// \brief Emit a check that \p V is the address of storage of the
Modified: cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp?rev=175078&r1=175077&r2=175078&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp Wed Feb 13 15:18:23 2013
@@ -6,6 +6,8 @@ struct S {
virtual int f();
};
+struct T : S {};
+
// CHECK: @_Z17reference_binding
void reference_binding(int *p, S *q) {
// C++ core issue 453: If an lvalue to which a reference is directly bound
@@ -173,3 +175,47 @@ int bad_enum_value() {
int c = e3;
return a + b + c;
}
+
+// CHECK: @_Z20bad_downcast_pointer
+void bad_downcast_pointer(S *p) {
+ // CHECK: %[[NONNULL:.*]] = icmp ne {{.*}}, null
+ // CHECK: br i1 %[[NONNULL]],
+
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64(
+ // CHECK: %[[E1:.*]] = icmp uge i64 %[[SIZE]], 24
+ // CHECK: %[[MISALIGN:.*]] = and i64 %{{.*}}, 7
+ // CHECK: %[[E2:.*]] = icmp eq i64 %[[MISALIGN]], 0
+ // CHECK: %[[E12:.*]] = and i1 %[[E1]], %[[E2]]
+ // CHECK: br i1 %[[E12]],
+
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ // CHECK: br label
+
+ // CHECK: br i1 %{{.*}},
+
+ // CHECK: call void @__ubsan_handle_dynamic_type_cache_miss
+ // CHECK: br label
+ (void) static_cast<T*>(p);
+}
+
+// CHECK: @_Z22bad_downcast_reference
+void bad_downcast_reference(S &p) {
+ // CHECK: %[[E1:.*]] = icmp ne {{.*}}, null
+ // CHECK-NOT: br i1
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64(
+ // CHECK: %[[E2:.*]] = icmp uge i64 %[[SIZE]], 24
+ // CHECK: %[[E12:.*]] = and i1 %[[E1]], %[[E2]]
+ // CHECK: %[[MISALIGN:.*]] = and i64 %{{.*}}, 7
+ // CHECK: %[[E3:.*]] = icmp eq i64 %[[MISALIGN]], 0
+ // CHECK: %[[E123:.*]] = and i1 %[[E12]], %[[E3]]
+ // CHECK: br i1 %[[E123]],
+
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ // CHECK: br label
+
+ // CHECK: br i1 %{{.*}},
+
+ // CHECK: call void @__ubsan_handle_dynamic_type_cache_miss
+ // CHECK: br label
+ (void) static_cast<T&>(p);
+}
More information about the cfe-commits
mailing list