[clang] [clang][win] Fix size passed to delete[] in vector deleting destructors (PR #172513)
Mariya Podchishchaeva via cfe-commits
cfe-commits at lists.llvm.org
Tue Dec 16 08:26:20 PST 2025
https://github.com/Fznamznon created https://github.com/llvm/llvm-project/pull/172513
Due to missing parameters only size of a single array element was passed.
Reported by https://github.com/llvm/llvm-project/pull/170337#issuecomment-3660304812
>From 367b89de70d3169751d159a4e2167c7287db96df Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <mariya.podchishchaeva at intel.com>
Date: Tue, 16 Dec 2025 07:31:45 -0800
Subject: [PATCH] [clang][win] Fix size passed to delete[] in vector deleting
dtor
Reported by https://github.com/llvm/llvm-project/pull/170337#issuecomment-3660304812
---
clang/lib/CodeGen/CGClass.cpp | 9 ++--
.../microsoft-vector-deleting-dtors.cpp | 36 ++++++++-----
.../microsoft-vector-deleting-dtors2.cpp | 8 +--
...svc-vector-deleting-dtors-sized-delete.cpp | 54 +++++++++++++++++++
.../msvc-vector-deleting-destructors.cpp | 8 ++-
.../PCH/msvc-vector-deleting-destructors.cpp | 8 ++-
6 files changed, 100 insertions(+), 23 deletions(-)
create mode 100644 clang/test/CodeGenCXX/msvc-vector-deleting-dtors-sized-delete.cpp
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 826f5799bae3c..a5096506f0ab1 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1502,7 +1502,8 @@ static void EmitConditionalArrayDtorCall(const CXXDestructorDecl *DD,
if (Dtor->getArrayOperatorDelete()) {
if (!Dtor->getGlobalArrayOperatorDelete()) {
CGF.EmitDeleteCall(Dtor->getArrayOperatorDelete(), allocatedPtr,
- CGF.getContext().getCanonicalTagType(ClassDecl));
+ CGF.getContext().getCanonicalTagType(ClassDecl),
+ numElements, cookieSize);
} else {
// If global operator[] is set, the class had its own operator delete[].
// In that case, check the 4th bit. If it is set, we need to call
@@ -1519,12 +1520,14 @@ static void EmitConditionalArrayDtorCall(const CXXDestructorDecl *DD,
CGF.Builder.CreateCondBr(ShouldCallGlobDelete, ClassDelete, GlobDelete);
CGF.EmitBlock(ClassDelete);
CGF.EmitDeleteCall(Dtor->getArrayOperatorDelete(), allocatedPtr,
- CGF.getContext().getCanonicalTagType(ClassDecl));
+ CGF.getContext().getCanonicalTagType(ClassDecl),
+ numElements, cookieSize);
CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
CGF.EmitBlock(GlobDelete);
CGF.EmitDeleteCall(Dtor->getGlobalArrayOperatorDelete(), allocatedPtr,
- CGF.getContext().getCanonicalTagType(ClassDecl));
+ CGF.getContext().getCanonicalTagType(ClassDecl),
+ numElements, cookieSize);
}
} else {
// No operators delete[] were found, so emit a trap.
diff --git a/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp b/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp
index e8012abb79aee..cbce869fb21b6 100644
--- a/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp
+++ b/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp
@@ -217,9 +217,13 @@ void bar() {
// CHECK-NEXT: %[[ISFIRSTBITZERO:.*]] = icmp eq i32 %[[FIRSTBIT]], 0
// CHECK-NEXT: br i1 %[[ISFIRSTBITZERO]], label %dtor.continue, label %dtor.call_delete_after_array_destroy
// CHECK: dtor.call_delete_after_array_destroy:
-// X64-NEXT: call void @"??_V at YAXPEAX_K@Z"(ptr noundef %[[COOKIEGEP]], i64 noundef 8)
-// X86-NEXT: call void @"??_V at YAXPAXI@Z"(ptr noundef %[[COOKIEGEP]], i32 noundef 4)
-// CHECK-NEXT: br label %dtor.continue
+// X64-NEXT: %[[ARRSZ:.*]] = mul i64 8, %[[HOWMANY]]
+// X86-NEXT: %[[ARRSZ:.*]] = mul i32 4, %[[HOWMANY]]
+// X64-NEXT: %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// X86-NEXT: %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// X64-NEXT: call void @"??_V at YAXPEAX_K@Z"(ptr noundef %[[COOKIEGEP]], i64 noundef %[[TOTALSZ]])
+// X86-NEXT: call void @"??_V at YAXPAXI@Z"(ptr noundef %[[COOKIEGEP]], i32 noundef %[[TOTALSZ]])
+// CHECK-NEXT: br label %dtor.continue
// CHECK: dtor.scalar:
// X64-NEXT: call void @"??1Parrot@@UEAA at XZ"(ptr noundef nonnull align 8 dereferenceable(8) %[[LTHIS]])
// X86-NEXT: call x86_thiscallcc void @"??1Parrot@@UAE at XZ"(ptr noundef nonnull align 4 dereferenceable(4) %[[LTHIS]])
@@ -252,8 +256,12 @@ void bar() {
// X86-NEXT: call void @"??_VHasOperatorDelete@@SAXPAX at Z"
// CHECK-NEXT: br label %dtor.continue
// CHECK: dtor.call_glob_delete_after_array_destroy:
-// X64-NEXT: call void @"??_V at YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 8)
-// X86-NEXT: call void @"??_V at YAXPAXI@Z"(ptr noundef %2, i32 noundef 4)
+// X64-NEXT: %[[ARRSZ:.*]] = mul i64 8, %[[COOKIE:.*]]
+// X86-NEXT: %[[ARRSZ:.*]] = mul i32 4, %[[COOKIE:.*]]
+// X64-NEXT: %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// X86-NEXT: %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// X64-NEXT: call void @"??_V at YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
+// X86-NEXT: call void @"??_V at YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
// CHECK-NEXT: br label %dtor.continue
@@ -314,22 +322,26 @@ void foobartest() {
// CHECK-NEXT: %5 = icmp eq i32 %4, 0
// CHECK-NEXT: br i1 %5, label %dtor.continue, label %dtor.call_delete_after_array_destroy
// CHECK: dtor.call_delete_after_array_destroy:
-// X64-NEXT: call void @"??_V at YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 16)
-// X86-NEXT: call void @"??_V at YAXPAXI@Z"(ptr noundef %2, i32 noundef 8)
+// X64-NEXT: %[[ARRSZ:.*]] = mul i64 16, %[[COOKIE:.*]]
+// X86-NEXT: %[[ARRSZ:.*]] = mul i32 8, %[[COOKIE:.*]]
+// X64-NEXT: %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// X86-NEXT: %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// X64-NEXT: call void @"??_V at YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
+// X86-NEXT: call void @"??_V at YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
// CHECK-NEXT: br label %dtor.continue
// CHECK: dtor.scalar:
// X64-NEXT: call void @"??1Derived@@UEAA at XZ"(ptr noundef nonnull align 8 dereferenceable(16) %this1)
// X86-NEXT: call x86_thiscallcc void @"??1Derived@@UAE at XZ"(ptr noundef nonnull align 4 dereferenceable(8) %this1)
-// CHECK-NEXT: %6 = and i32 %should_call_delete2, 1
-// CHECK-NEXT: %7 = icmp eq i32 %6, 0
-// CHECK-NEXT: br i1 %7, label %dtor.continue, label %dtor.call_delete
+// CHECK-NEXT: %8 = and i32 %should_call_delete2, 1
+// CHECK-NEXT: %9 = icmp eq i32 %8, 0
+// CHECK-NEXT: br i1 %9, label %dtor.continue, label %dtor.call_delete
// CHECK: dtor.call_delete:
// X64-NEXT: call void @"??3 at YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef 16)
// X86-NEXT: call void @"??3 at YAXPAXI@Z"(ptr noundef %this1, i32 noundef 8)
// CHECK-NEXT: br label %dtor.continue
// CHECK: dtor.continue:
-// CHECK-NEXT: %8 = load ptr, ptr %retval
-// CHECK-NEXT: ret ptr %8
+// CHECK-NEXT: %10 = load ptr, ptr %retval
+// CHECK-NEXT: ret ptr %10
// X64: define weak dso_local noundef ptr @"??_EAllocatedAsArray@@UEAAPEAXI at Z"
// X86: define weak dso_local x86_thiscallcc noundef ptr @"??_EAllocatedAsArray@@UAEPAXI at Z"
diff --git a/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors2.cpp b/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors2.cpp
index 1b1564227c40f..b16cb30d7133f 100644
--- a/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors2.cpp
+++ b/clang/test/CodeGenCXX/microsoft-vector-deleting-dtors2.cpp
@@ -59,9 +59,9 @@ void TesttheTest() {
// X64: define weak dso_local noundef ptr @"??_EDrawingBuffer@@UEAAPEAXI at Z"
// X64: call void @"??1DrawingBuffer@@UEAA at XZ"(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)
// X64: call void @"??_V?$RefCounted at UDrawingBuffer@@@@SAXPEAX at Z"(ptr noundef %2)
-// X64: call void @"??_V at YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 8)
+// X64: call void @"??_V at YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %{{.*}})
// X64: call void @"??1DrawingBuffer@@UEAA at XZ"(ptr noundef nonnull align 8 dereferenceable(8) %this1)
-// X64: call void @"??3 at YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef 8)
+// X64: call void @"??3 at YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef {{.*}})
// X86: define dso_local void @"??3 at YAXPAXI@Z"(ptr noundef %0, i32 noundef %1)
@@ -70,9 +70,9 @@ void TesttheTest() {
// X86: define weak dso_local x86_thiscallcc noundef ptr @"??_EDrawingBuffer@@UAEPAXI at Z"
// X86: call x86_thiscallcc void @"??1DrawingBuffer@@UAE at XZ"(ptr noundef nonnull align 4 dereferenceable(4) %arraydestroy.element)
// X86: call void @"??_V?$RefCounted at UDrawingBuffer@@@@SAXPAX at Z"(ptr noundef %2)
-// X86: call void @"??_V at YAXPAXI@Z"(ptr noundef %2, i32 noundef 4)
+// X86: call void @"??_V at YAXPAXI@Z"(ptr noundef %2, i32 noundef {{.*}})
// X86 call x86_thiscallcc void @"??1DrawingBuffer@@UAE at XZ"(ptr noundef nonnull align 4 dereferenceable(4) %this1)
-// X86: call void @"??3 at YAXPAXI@Z"(ptr noundef %this1, i32 noundef 4)
+// X86: call void @"??3 at YAXPAXI@Z"(ptr noundef %this1, i32 noundef {{.*}})
// X64: define weak dso_local noundef ptr @"??_ETest@@UEAAPEAXI at Z"(ptr noundef nonnull align 8 dereferenceable(8) %this, i32 noundef %should_call_delete)
diff --git a/clang/test/CodeGenCXX/msvc-vector-deleting-dtors-sized-delete.cpp b/clang/test/CodeGenCXX/msvc-vector-deleting-dtors-sized-delete.cpp
new file mode 100644
index 0000000000000..6c9faa88e08e9
--- /dev/null
+++ b/clang/test/CodeGenCXX/msvc-vector-deleting-dtors-sized-delete.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -emit-llvm -fms-extensions %s -triple=x86_64-pc-windows-msvc -o - | FileCheck --check-prefixes=X64,CHECK %s
+// RUN: %clang_cc1 -emit-llvm -fms-extensions %s -triple=i386-pc-windows-msvc -o - | FileCheck --check-prefixes=X86,CHECK %s
+
+using size_t = __SIZE_TYPE__;
+void operator delete[](void *ptr, size_t sz) { }
+
+struct Test {
+ virtual ~Test() {}
+ void operator delete[](void *ptr, size_t sz) { }
+ int x;
+ int y;
+};
+
+void test() {
+ Test* a = new Test[10];
+ delete[] a;
+}
+
+// X64: define weak dso_local noundef ptr @"??_ETest@@UEAAPEAXI at Z"(
+// X64-SAME: ptr {{.*}} %[[THIS:.*]], i32 {{.*}} %[[IMPLICIT_PARAM:.*]])
+// X86: define weak dso_local x86_thiscallcc noundef ptr @"??_ETest@@UAEPAXI at Z"(
+// X86-SAME: ptr {{.*}} %[[THIS:.*]], i32 {{.*}} %[[IMPLICIT_PARAM:.*]])
+// CHECK: entry:
+// CHECK-NEXT: %[[RET:.*]] = alloca ptr
+// CHECK-NEXT: %[[IPADDR:.*]] = alloca i32
+// CHECK-NEXT: %[[THISADDR:.*]] = alloca ptr
+// CHECK-NEXT: store i32 %[[IMPLICIT_PARAM]], ptr %[[IPADDR]]
+// CHECK-NEXT: store ptr %[[THIS]], ptr %[[THISADDR]]
+// CHECK-NEXT: %[[LTHIS:.*]] = load ptr, ptr %[[THISADDR]]
+// CHECK-NEXT: store ptr %[[LTHIS]], ptr %[[RET]]
+// CHECK-NEXT: %[[LIP:.*]] = load i32, ptr %[[IPADDR]]
+// CHECK-NEXT: %[[SECONDBIT:.*]] = and i32 %[[LIP]], 2
+// CHECK-NEXT: %[[ISSECONDBITZERO:.*]] = icmp eq i32 %[[SECONDBIT]], 0
+// CHECK-NEXT: br i1 %[[ISSECONDBITZERO:.*]], label %dtor.scalar, label %dtor.vector
+// CHECK: dtor.vector:
+// X64-NEXT: %[[COOKIEGEP:.*]] = getelementptr inbounds i8, ptr %[[LTHIS]], i64 -8
+// X86-NEXT: %[[COOKIEGEP:.*]] = getelementptr inbounds i8, ptr %[[LTHIS]], i32 -4
+// X64-NEXT: %[[HOWMANY:.*]] = load i64, ptr %[[COOKIEGEP]]
+// X86-NEXT: %[[HOWMANY:.*]] = load i32, ptr %[[COOKIEGEP]]
+// CHECK: dtor.call_class_delete_after_array_destroy:
+// X64-NEXT: %[[ARRSZ:.*]] = mul i64 16, %[[HOWMANY]]
+// X86-NEXT: %[[ARRSZ:.*]] = mul i32 12, %[[HOWMANY]]
+// X64-NEXT: %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// X86-NEXT: %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// X64-NEXT: call void @"??_VTest@@SAXPEAX_K at Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
+// X86-NEXT: call void @"??_VTest@@SAXPAXI at Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
+
+// CHECK: dtor.call_glob_delete_after_array_destroy:
+// X64-NEXT: %[[ARRSZ1:.*]] = mul i64 16, %[[HOWMANY]]
+// X86-NEXT: %[[ARRSZ1:.*]] = mul i32 12, %[[HOWMANY]]
+// X64-NEXT: %[[TOTALSZ1:.*]] = add i64 %[[ARRSZ1]], 8
+// X86-NEXT: %[[TOTALSZ1:.*]] = add i32 %[[ARRSZ1]], 4
+// X64-NEXT: call void @"??_V at YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ1]])
+// X86-NEXT: call void @"??_V at YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ1]])
diff --git a/clang/test/Modules/msvc-vector-deleting-destructors.cpp b/clang/test/Modules/msvc-vector-deleting-destructors.cpp
index a0806054355db..68faa687251d7 100644
--- a/clang/test/Modules/msvc-vector-deleting-destructors.cpp
+++ b/clang/test/Modules/msvc-vector-deleting-destructors.cpp
@@ -20,8 +20,12 @@ void out_of_module_tests(Derived *p, Derived *p1) {
// CHECK32-NEXT: call void @"??_VBase1@@SAXPAX at Z"(ptr noundef %2)
// CHECK64-NEXT: call void @"??_VBase1@@SAXPEAX at Z"(ptr noundef %2)
// CHECK: dtor.call_glob_delete_after_array_destroy:
-// CHECK32-NEXT: call void @"??_V at YAXPAXI@Z"(ptr noundef %2, i32 noundef 8)
-// CHECK64-NEXT: call void @"??_V at YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 16)
+// CHECK64-NEXT: %[[ARRSZ:.*]] = mul i64 16, %[[COOKIE:.*]]
+// CHECK32-NEXT: %[[ARRSZ:.*]] = mul i32 8, %[[COOKIE:.*]]
+// CHECK64-NEXT: %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// CHECK32-NEXT: %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// CHECK32-NEXT: call void @"??_V at YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
+// CHECK64-NEXT: call void @"??_V at YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
// CHECK: dtor.call_glob_delete:
// CHECK32-NEXT: call void @"??3 at YAXPAXI@Z"(ptr noundef %this1, i32 noundef 8)
// CHECK64-NEXT: call void @"??3 at YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef 16)
diff --git a/clang/test/PCH/msvc-vector-deleting-destructors.cpp b/clang/test/PCH/msvc-vector-deleting-destructors.cpp
index f548dba8efd20..1409b41d2df82 100644
--- a/clang/test/PCH/msvc-vector-deleting-destructors.cpp
+++ b/clang/test/PCH/msvc-vector-deleting-destructors.cpp
@@ -24,8 +24,12 @@ void out_of_module_tests(Derived *p, Derived *p1) {
// CHECK32-NEXT: call void @"??_VBase1@@SAXPAX at Z"(ptr noundef %2)
// CHECK64-NEXT: call void @"??_VBase1@@SAXPEAX at Z"(ptr noundef %2)
// CHECK: dtor.call_glob_delete_after_array_destroy:
-// CHECK32-NEXT: call void @"??_V at YAXPAXI@Z"(ptr noundef %2, i32 noundef 8)
-// CHECK64-NEXT: call void @"??_V at YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 16)
+// CHECK64-NEXT: %[[ARRSZ:.*]] = mul i64 16, %[[COOKIE:.*]]
+// CHECK32-NEXT: %[[ARRSZ:.*]] = mul i32 8, %[[COOKIE:.*]]
+// CHECK64-NEXT: %[[TOTALSZ:.*]] = add i64 %[[ARRSZ]], 8
+// CHECK32-NEXT: %[[TOTALSZ:.*]] = add i32 %[[ARRSZ]], 4
+// CHECK32-NEXT: call void @"??_V at YAXPAXI@Z"(ptr noundef %2, i32 noundef %[[TOTALSZ]])
+// CHECK64-NEXT: call void @"??_V at YAXPEAX_K@Z"(ptr noundef %2, i64 noundef %[[TOTALSZ]])
// CHECK: dtor.call_glob_delete:
// CHECK32-NEXT: call void @"??3 at YAXPAXI@Z"(ptr noundef %this1, i32 noundef 8)
// CHECK64-NEXT: call void @"??3 at YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef 16)
More information about the cfe-commits
mailing list