[clang] [MS][clang] Fix crash on deletion of array of pointers (PR #134088)

Mariya Podchishchaeva via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 2 07:07:04 PDT 2025


https://github.com/Fznamznon created https://github.com/llvm/llvm-project/pull/134088

Sometimes a non-array delete is treated as delete[] when input pointer is pointer to array. With vector deleting destructors support we now generate a virtual destructor call instead of simple loop over the elements. This patch adjusts the codepath that generates virtual call to expect the case of pointer to array.

>From 0d2b22f9af7868ec7b1f8b908fd61b791ea8434b Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <mariya.podchishchaeva at intel.com>
Date: Wed, 2 Apr 2025 06:35:12 -0700
Subject: [PATCH] [MS][clang] Fix crash on deletion of array of pointers

Sometimes a non-array delete is treated as delete[] when input pointer
is pointer to array. With vector deleting destructors support we now
generate a virtual destructor call instead of simple loop over the
elements. This patch adjusts the codepath that generates virtual call to
expect the case of pointer to array.
---
 clang/lib/AST/Expr.cpp                        |  3 ++
 clang/lib/CodeGen/MicrosoftCXXABI.cpp         |  3 ++
 .../microsoft-vector-deleting-dtors.cpp       | 47 +++++++++++++++++++
 3 files changed, 53 insertions(+)

diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 9d5b4a60c9fe7..e7c3302f24756 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -71,6 +71,9 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const {
   if (const PointerType *PTy = DerivedType->getAs<PointerType>())
     DerivedType = PTy->getPointeeType();
 
+  while (const ArrayType *ATy = DerivedType->getAsArrayTypeUnsafe())
+    DerivedType = ATy->getElementType();
+
   if (DerivedType->isDependentType())
     return nullptr;
 
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 464d4370284fb..ccf24e0a3ebd7 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -2033,6 +2033,9 @@ llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall(
     ThisTy = D->getDestroyedType();
   }
 
+  while (const ArrayType *ATy = ThisTy->getAsArrayTypeUnsafe())
+    ThisTy = ATy->getElementType();
+
   This = adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true);
   RValue RV =
       CGF.EmitCXXDestructorCall(GD, Callee, This.emitRawPointer(CGF), ThisTy,
diff --git a/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp b/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp
index 439ff84456033..9d23708602a43 100644
--- a/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp
+++ b/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp
@@ -35,6 +35,10 @@ void operator delete(void *p) { i-=2; }
 void operator delete[](void *p) { i--; }
 };
 
+struct AllocatedAsArray : public Bird {
+
+};
+
 // Vector deleting dtor for Bird is an alias because no new Bird[] expressions
 // in the TU.
 // X64: @"??_EBird@@UEAAPEAXI at Z" = weak dso_local unnamed_addr alias ptr (ptr, i32), ptr @"??_GBird@@UEAAPEAXI at Z"
@@ -55,6 +59,14 @@ Bird* alloc() {
   return P;
 }
 
+
+template<class C>
+struct S {
+  void foo() { void *p = new C(); delete (C *)p; }
+};
+
+S<AllocatedAsArray[1][3]> sp;
+
 void bar() {
   dealloc(alloc());
 
@@ -63,6 +75,8 @@ void bar() {
 
   Bird *p = new HasOperatorDelete[2];
   dealloc(p);
+
+  sp.foo();
 }
 
 // CHECK-LABEL: define dso_local void @{{.*}}dealloc{{.*}}(
@@ -99,6 +113,36 @@ void bar() {
 // CHECK: delete.end:
 // CHECK-NEXT:   ret void
 
+// Definition of S::foo, check that it has vector deleting destructor call
+// X64-LABEL: define linkonce_odr dso_local void @"?foo@?$S@$$BY102UAllocatedAsArray@@@@QEAAXXZ"
+// X86-LABEL: define linkonce_odr dso_local x86_thiscallcc void @"?foo@?$S@$$BY102UAllocatedAsArray@@@@QAEXXZ"
+// CHECK: delete.notnull:                                   ; preds = %arrayctor.cont
+// CHECK-NEXT:   %[[DEL_PTR:.*]] = getelementptr inbounds [1 x [3 x %struct.AllocatedAsArray]], ptr %[[THE_ARRAY:.*]], i32 0, i32 0
+// X64-NEXT:   %[[COOKIEGEP:.*]] = getelementptr inbounds i8, ptr %[[DEL_PTR]], i64 -8
+// X86-NEXT:   %[[COOKIEGEP:.*]] = getelementptr inbounds i8, ptr %[[DEL_PTR]], i32 -4
+// X64-NEXT:   %[[HOWMANY:.*]] = load i64, ptr %[[COOKIEGEP]]
+// X86-NEXT:   %[[HOWMANY:.*]] = load i32, ptr %[[COOKIEGEP]]
+// X64-NEXT:   %[[ISNOELEM:.*]] = icmp eq i64 %[[HOWMANY]], 0
+// X86-NEXT:   %[[ISNOELEM:.*]] = icmp eq i32 %[[HOWMANY]], 0
+// CHECK-NEXT:   br i1 %[[ISNOELEM]], label %vdtor.nocall, label %vdtor.call
+// CHECK: vdtor.nocall:                                     ; preds = %delete.notnull
+// X64-NEXT:   %[[HOWMANYBYTES:.*]] = mul i64 8, %[[HOWMANY]]
+// X86-NEXT:   %[[HOWMANYBYTES:.*]] = mul i32 4, %[[HOWMANY]]
+// X64-NEXT:   %[[ADDCOOKIESIZE:.*]] = add i64 %[[HOWMANYBYTES]], 8
+// X86-NEXT:   %[[ADDCOOKIESIZE:.*]] = add i32 %[[HOWMANYBYTES]], 4
+// X64-NEXT:   call void @"??_V at YAXPEAX_K@Z"(ptr noundef %[[COOKIEGEP]], i64 noundef %[[ADDCOOKIESIZE]])
+// X86-NEXT:   call void @"??_V at YAXPAXI@Z"(ptr noundef %[[COOKIEGEP]], i32 noundef %[[ADDCOOKIESIZE]])
+// CHECK-NEXT:   br label %delete.end
+// CHECK: vdtor.call:                                       ; preds = %delete.notnull
+// CHECK-NEXT:   %[[VTABLE:.*]] = load ptr, ptr %[[DEL_PTR]]
+// CHECK-NEXT:   %[[FPGEP:.*]] = getelementptr inbounds ptr, ptr %[[VTABLE]], i64 0
+// CHECK-NEXT:   %[[FPLOAD:.*]]  = load ptr, ptr %[[FPGEP]]
+// X64-NEXT:   %[[CALL:.*]] = call noundef ptr %[[FPLOAD]](ptr noundef nonnull align 8 dereferenceable(8) %[[DEL_PTR]], i32 noundef 3)
+// X86-NEXT:   %[[CALL:.*]] = call x86_thiscallcc noundef ptr %[[FPLOAD]](ptr noundef nonnull align 4 dereferenceable(4) %[[DEL_PTR]], i32 noundef 3)
+// CHECK-NEXT:   br label %delete.end
+// CHECK: delete.end:
+// CHECK-NEXT:   ret void
+
 // Vector dtor definition for Parrot.
 // X64-LABEL: define weak dso_local noundef ptr @"??_EParrot@@UEAAPEAXI at Z"(
 // X64-SAME: ptr {{.*}} %[[THIS:.*]], i32 {{.*}} %[[IMPLICIT_PARAM:.*]]) unnamed_addr
@@ -169,3 +213,6 @@ void bar() {
 // CHECK: dtor.call_delete:
 // X64-NEXT: call void @"??3HasOperatorDelete@@SAXPEAX at Z"
 // X86-NEXT: call void @"??3HasOperatorDelete@@SAXPAX at Z"
+
+// X64: define weak dso_local noundef ptr @"??_EAllocatedAsArray@@UEAAPEAXI at Z"
+// X86: define weak dso_local x86_thiscallcc noundef ptr @"??_EAllocatedAsArray@@UAEPAXI at Z"



More information about the cfe-commits mailing list