[cfe-commits] r164597 - in /cfe/trunk: lib/CodeGen/CGCXXABI.h lib/CodeGen/CGExprCXX.cpp lib/CodeGen/ItaniumCXXABI.cpp lib/CodeGen/MicrosoftCXXABI.cpp test/CodeGenCXX/delete.cpp

John McCall rjmccall at apple.com
Tue Sep 25 03:10:39 PDT 2012


Author: rjmccall
Date: Tue Sep 25 05:10:39 2012
New Revision: 164597

URL: http://llvm.org/viewvc/llvm-project?rev=164597&view=rev
Log:
When performing a ::delete of an object with a virtual destructor,
be sure to delete the complete object pointer, not the original
pointer.  This is necessary if the base being deleted is at a
non-zero offset in the complete object.  This is only required
for objects with virtual destructors because deleting an object
via a base-class subobject when the base does not have a virtual
destructor is undefined behavior.

Noticed while reviewing the last four years of cxx-abi-dev
activity.

Modified:
    cfe/trunk/lib/CodeGen/CGCXXABI.h
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/delete.cpp

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=164597&r1=164596&r2=164597&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Tue Sep 25 05:10:39 2012
@@ -154,6 +154,15 @@
   llvm::Constant *getMemberPointerAdjustment(const CastExpr *E);
 
 public:
+  /// Adjust the given non-null pointer to an object of polymorphic
+  /// type to point to the complete object.
+  ///
+  /// The IR type of the result should be a pointer but is otherwise
+  /// irrelevant.
+  virtual llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
+                                              llvm::Value *ptr,
+                                              QualType type) = 0;
+
   /// Build the signature of the given constructor variant by adding
   /// any required parameters.  For convenience, ResTy has been
   /// initialized to 'void', and ArgTys has been initialized with the

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=164597&r1=164596&r2=164597&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Tue Sep 25 05:10:39 2012
@@ -1382,8 +1382,14 @@
         if (UseGlobalDelete) {
           // If we're supposed to call the global delete, make sure we do so
           // even if the destructor throws.
+
+          // Derive the complete-object pointer, which is what we need
+          // to pass to the deallocation function.
+          llvm::Value *completePtr =
+            CGF.CGM.getCXXABI().adjustToCompleteObject(CGF, Ptr, ElementType);
+
           CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup,
-                                                    Ptr, OperatorDelete, 
+                                                    completePtr, OperatorDelete,
                                                     ElementType);
         }
         

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=164597&r1=164596&r2=164597&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Tue Sep 25 05:10:39 2012
@@ -92,6 +92,10 @@
                                           llvm::Value *Addr,
                                           const MemberPointerType *MPT);
 
+  llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
+                                      llvm::Value *ptr,
+                                      QualType type);
+
   void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
                                  CXXCtorType T,
                                  CanQualType &ResTy,
@@ -677,6 +681,25 @@
   return MPT->getPointeeType()->isFunctionType();
 }
 
+/// The Itanium ABI always places an offset to the complete object
+/// at entry -2 in the vtable.
+llvm::Value *ItaniumCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
+                                                   llvm::Value *ptr,
+                                                   QualType type) {
+  // Grab the vtable pointer as an intptr_t*.
+  llvm::Value *vtable = CGF.GetVTablePtr(ptr, CGF.IntPtrTy->getPointerTo());
+
+  // Track back to entry -2 and pull out the offset there.
+  llvm::Value *offsetPtr = 
+    CGF.Builder.CreateConstInBoundsGEP1_64(vtable, -2, "complete-offset.ptr");
+  llvm::LoadInst *offset = CGF.Builder.CreateLoad(offsetPtr);
+  offset->setAlignment(CGF.PointerAlignInBytes);
+
+  // Apply the offset.
+  ptr = CGF.Builder.CreateBitCast(ptr, CGF.Int8PtrTy);
+  return CGF.Builder.CreateInBoundsGEP(ptr, offset);
+}
+
 /// The generic ABI passes 'this', plus a VTT if it's initializing a
 /// base subobject.
 void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=164597&r1=164596&r2=164597&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Tue Sep 25 05:10:39 2012
@@ -30,6 +30,10 @@
 
   StringRef GetPureVirtualCallName() { return "_purecall"; }
 
+  llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
+                                      llvm::Value *ptr,
+                                      QualType type);
+
   void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
                                  CXXCtorType Type,
                                  CanQualType &ResTy,
@@ -95,6 +99,13 @@
 
 }
 
+llvm::Value *MicrosoftCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
+                                                     llvm::Value *ptr,
+                                                     QualType type) {
+  // FIXME: implement
+  return ptr;
+}
+
 bool MicrosoftCXXABI::needThisReturn(GlobalDecl GD) {
   const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
   return isa<CXXConstructorDecl>(MD);

Modified: cfe/trunk/test/CodeGenCXX/delete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/delete.cpp?rev=164597&r1=164596&r2=164597&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/delete.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/delete.cpp Tue Sep 25 05:10:39 2012
@@ -113,12 +113,23 @@
 
   // CHECK: define void @_ZN5test421global_delete_virtualEPNS_1XE
   void global_delete_virtual(X *xp) {
-    // CHECK: [[VTABLE:%.*]] = load void ([[X:%.*]])***
-    // CHECK-NEXT: [[VFN:%.*]] = getelementptr inbounds void ([[X]])** [[VTABLE]], i64 0
-    // CHECK-NEXT: [[VFNPTR:%.*]] = load void ([[X]])** [[VFN]]
-    // CHECK-NEXT: call void [[VFNPTR]]([[X]] [[OBJ:%.*]])
-    // CHECK-NEXT: [[OBJVOID:%.*]] = bitcast [[X]] [[OBJ]] to i8*
-    // CHECK-NEXT: call void @_ZdlPv(i8* [[OBJVOID]]) nounwind
+    //   Load the offset-to-top from the vtable and apply it.
+    //   This has to be done first because the dtor can mess it up.
+    // CHECK:      [[T0:%.*]] = bitcast [[X:%.*]]* [[XP:%.*]] to i64**
+    // CHECK-NEXT: [[VTABLE:%.*]] = load i64** [[T0]]
+    // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds i64* [[VTABLE]], i64 -2
+    // CHECK-NEXT: [[OFFSET:%.*]] = load i64* [[T0]], align 8
+    // CHECK-NEXT: [[T0:%.*]] = bitcast [[X]]* [[XP]] to i8*
+    // CHECK-NEXT: [[ALLOCATED:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[OFFSET]]
+    //   Load the complete-object destructor (not the deleting destructor)
+    //   and call it.
+    // CHECK-NEXT: [[T0:%.*]] = bitcast [[X:%.*]]* [[XP:%.*]] to void ([[X]]*)***
+    // CHECK-NEXT: [[VTABLE:%.*]] = load void ([[X]]*)*** [[T0]]
+    // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds void ([[X]]*)** [[VTABLE]], i64 0
+    // CHECK-NEXT: [[DTOR:%.*]] = load void ([[X]]*)** [[T0]]
+    // CHECK-NEXT: call void [[DTOR]]([[X]]* [[OBJ:%.*]])
+    //   Call the global operator delete.
+    // CHECK-NEXT: call void @_ZdlPv(i8* [[ALLOCATED]]) nounwind
     ::delete xp;
   }
 }





More information about the cfe-commits mailing list