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