Skip to content

Commit 22130ca

Browse files
authored
[MS][clang] Fix crash on deletion of array of pointers (#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.
1 parent 78a4b9d commit 22130ca

File tree

3 files changed

+53
-0
lines changed

3 files changed

+53
-0
lines changed

clang/lib/AST/Expr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const {
7171
if (const PointerType *PTy = DerivedType->getAs<PointerType>())
7272
DerivedType = PTy->getPointeeType();
7373

74+
while (const ArrayType *ATy = DerivedType->getAsArrayTypeUnsafe())
75+
DerivedType = ATy->getElementType();
76+
7477
if (DerivedType->isDependentType())
7578
return nullptr;
7679

clang/lib/CodeGen/MicrosoftCXXABI.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2034,6 +2034,9 @@ llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall(
20342034
ThisTy = D->getDestroyedType();
20352035
}
20362036

2037+
while (const ArrayType *ATy = Context.getAsArrayType(ThisTy))
2038+
ThisTy = ATy->getElementType();
2039+
20372040
This = adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true);
20382041
RValue RV =
20392042
CGF.EmitCXXDestructorCall(GD, Callee, This.emitRawPointer(CGF), ThisTy,

clang/test/CodeGenCXX/microsoft-vector-deleting-dtors.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ void operator delete(void *p) { i-=2; }
3535
void operator delete[](void *p) { i--; }
3636
};
3737

38+
struct AllocatedAsArray : public Bird {
39+
40+
};
41+
3842
// Vector deleting dtor for Bird is an alias because no new Bird[] expressions
3943
// in the TU.
4044
// X64: @"??_EBird@@UEAAPEAXI@Z" = weak dso_local unnamed_addr alias ptr (ptr, i32), ptr @"??_GBird@@UEAAPEAXI@Z"
@@ -55,6 +59,14 @@ Bird* alloc() {
5559
return P;
5660
}
5761

62+
63+
template<class C>
64+
struct S {
65+
void foo() { void *p = new C(); delete (C *)p; }
66+
};
67+
68+
S<AllocatedAsArray[1][3]> sp;
69+
5870
void bar() {
5971
dealloc(alloc());
6072

@@ -63,6 +75,8 @@ void bar() {
6375

6476
Bird *p = new HasOperatorDelete[2];
6577
dealloc(p);
78+
79+
sp.foo();
6680
}
6781

6882
// CHECK-LABEL: define dso_local void @{{.*}}dealloc{{.*}}(
@@ -99,6 +113,36 @@ void bar() {
99113
// CHECK: delete.end:
100114
// CHECK-NEXT: ret void
101115

116+
// Definition of S::foo, check that it has vector deleting destructor call
117+
// X64-LABEL: define linkonce_odr dso_local void @"?foo@?$S@$$BY102UAllocatedAsArray@@@@QEAAXXZ"
118+
// X86-LABEL: define linkonce_odr dso_local x86_thiscallcc void @"?foo@?$S@$$BY102UAllocatedAsArray@@@@QAEXXZ"
119+
// CHECK: delete.notnull: ; preds = %arrayctor.cont
120+
// CHECK-NEXT: %[[DEL_PTR:.*]] = getelementptr inbounds [1 x [3 x %struct.AllocatedAsArray]], ptr %[[THE_ARRAY:.*]], i32 0, i32 0
121+
// X64-NEXT: %[[COOKIEGEP:.*]] = getelementptr inbounds i8, ptr %[[DEL_PTR]], i64 -8
122+
// X86-NEXT: %[[COOKIEGEP:.*]] = getelementptr inbounds i8, ptr %[[DEL_PTR]], i32 -4
123+
// X64-NEXT: %[[HOWMANY:.*]] = load i64, ptr %[[COOKIEGEP]]
124+
// X86-NEXT: %[[HOWMANY:.*]] = load i32, ptr %[[COOKIEGEP]]
125+
// X64-NEXT: %[[ISNOELEM:.*]] = icmp eq i64 %[[HOWMANY]], 0
126+
// X86-NEXT: %[[ISNOELEM:.*]] = icmp eq i32 %[[HOWMANY]], 0
127+
// CHECK-NEXT: br i1 %[[ISNOELEM]], label %vdtor.nocall, label %vdtor.call
128+
// CHECK: vdtor.nocall: ; preds = %delete.notnull
129+
// X64-NEXT: %[[HOWMANYBYTES:.*]] = mul i64 8, %[[HOWMANY]]
130+
// X86-NEXT: %[[HOWMANYBYTES:.*]] = mul i32 4, %[[HOWMANY]]
131+
// X64-NEXT: %[[ADDCOOKIESIZE:.*]] = add i64 %[[HOWMANYBYTES]], 8
132+
// X86-NEXT: %[[ADDCOOKIESIZE:.*]] = add i32 %[[HOWMANYBYTES]], 4
133+
// X64-NEXT: call void @"??_V@YAXPEAX_K@Z"(ptr noundef %[[COOKIEGEP]], i64 noundef %[[ADDCOOKIESIZE]])
134+
// X86-NEXT: call void @"??_V@YAXPAXI@Z"(ptr noundef %[[COOKIEGEP]], i32 noundef %[[ADDCOOKIESIZE]])
135+
// CHECK-NEXT: br label %delete.end
136+
// CHECK: vdtor.call: ; preds = %delete.notnull
137+
// CHECK-NEXT: %[[VTABLE:.*]] = load ptr, ptr %[[DEL_PTR]]
138+
// CHECK-NEXT: %[[FPGEP:.*]] = getelementptr inbounds ptr, ptr %[[VTABLE]], i64 0
139+
// CHECK-NEXT: %[[FPLOAD:.*]] = load ptr, ptr %[[FPGEP]]
140+
// X64-NEXT: %[[CALL:.*]] = call noundef ptr %[[FPLOAD]](ptr noundef nonnull align 8 dereferenceable(8) %[[DEL_PTR]], i32 noundef 3)
141+
// X86-NEXT: %[[CALL:.*]] = call x86_thiscallcc noundef ptr %[[FPLOAD]](ptr noundef nonnull align 4 dereferenceable(4) %[[DEL_PTR]], i32 noundef 3)
142+
// CHECK-NEXT: br label %delete.end
143+
// CHECK: delete.end:
144+
// CHECK-NEXT: ret void
145+
102146
// Vector dtor definition for Parrot.
103147
// X64-LABEL: define weak dso_local noundef ptr @"??_EParrot@@UEAAPEAXI@Z"(
104148
// X64-SAME: ptr {{.*}} %[[THIS:.*]], i32 {{.*}} %[[IMPLICIT_PARAM:.*]]) unnamed_addr
@@ -169,3 +213,6 @@ void bar() {
169213
// CHECK: dtor.call_delete:
170214
// X64-NEXT: call void @"??3HasOperatorDelete@@SAXPEAX@Z"
171215
// X86-NEXT: call void @"??3HasOperatorDelete@@SAXPAX@Z"
216+
217+
// X64: define weak dso_local noundef ptr @"??_EAllocatedAsArray@@UEAAPEAXI@Z"
218+
// X86: define weak dso_local x86_thiscallcc noundef ptr @"??_EAllocatedAsArray@@UAEPAXI@Z"

0 commit comments

Comments
 (0)