From 87b4b0ec46f058bef8fffc6385ab3566c56d8378 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 24 Jul 2025 20:52:18 -0700 Subject: [PATCH] IRGen: correct some type deletion ASAN identified mismatched `operator new` and `operator delete` on these types. The reason for this is the sized allocation for the tail packing involved. Provide the associated `operator delete` that releases the memory. Note that the `operator delete` is static and does not have the implicit `this` pointer, and we cannot use the name `this` for the variable. --- lib/IRGen/CMakeLists.txt | 2 ++ lib/IRGen/GenExistential.cpp | 14 +++++++++++--- lib/IRGen/GenRecord.h | 7 +++++++ lib/IRGen/ProtocolInfo.h | 7 +++++++ 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/IRGen/CMakeLists.txt b/lib/IRGen/CMakeLists.txt index e1fc4379b0dfd..2782386daed71 100644 --- a/lib/IRGen/CMakeLists.txt +++ b/lib/IRGen/CMakeLists.txt @@ -76,6 +76,8 @@ add_swift_host_library(swiftIRGen STATIC transformutils irprinter ) +target_compile_options(swiftIRGen PRIVATE + $<$,$>:-fsized-deallocation>) target_link_libraries(swiftIRGen INTERFACE clangCodeGen clangAST) diff --git a/lib/IRGen/GenExistential.cpp b/lib/IRGen/GenExistential.cpp index f364c0e4d5cff..5e0d4af15359d 100644 --- a/lib/IRGen/GenExistential.cpp +++ b/lib/IRGen/GenExistential.cpp @@ -130,6 +130,7 @@ namespace { class ExistentialTypeInfoBase : public Base, private llvm::TrailingObjects { friend class llvm::TrailingObjects; + using Tail = llvm::TrailingObjects; /// The number of non-trivial protocols for this existential. unsigned NumStoredProtocols; @@ -157,12 +158,19 @@ namespace { create(ArrayRef protocols, As &&...args) { void *buffer = operator new( - llvm::TrailingObjects:: - template totalSizeToAlloc( - protocols.size())); + Tail::template totalSizeToAlloc( + protocols.size())); return new (buffer) Derived(protocols, std::forward(args)...); } + void operator delete(void *ptr) { + const auto *pThis = static_cast(ptr); + const size_t count = pThis->NumStoredProtocols; + const size_t size = + Tail::template totalSizeToAlloc(count); + ::operator delete(ptr, size); + } + /// Returns the number of protocol witness tables directly carried /// by values of this type. unsigned getNumStoredProtocols() const { return NumStoredProtocols; } diff --git a/lib/IRGen/GenRecord.h b/lib/IRGen/GenRecord.h index eaee3f2f94894..65acff49edccf 100644 --- a/lib/IRGen/GenRecord.h +++ b/lib/IRGen/GenRecord.h @@ -157,6 +157,13 @@ class RecordTypeInfoImpl : public Base, return new(buffer) Impl(fields, std::forward(args)...); } + void operator delete(void *ptr) { + const auto *pThis = static_cast(ptr); + const size_t count = pThis->NumFields; + const size_t size = Impl::template totalSizeToAlloc(count); + ::operator delete(ptr, size); + } + bool areFieldsABIAccessible() const { return AreFieldsABIAccessible; } diff --git a/lib/IRGen/ProtocolInfo.h b/lib/IRGen/ProtocolInfo.h index 44de7cf7ec7f1..8c4180cb549c1 100644 --- a/lib/IRGen/ProtocolInfo.h +++ b/lib/IRGen/ProtocolInfo.h @@ -230,6 +230,13 @@ class ProtocolInfo final : ProtocolInfoKind kind); public: + void operator delete(void *ptr) { + const auto *pThis = static_cast(ptr); + const size_t count = pThis->NumTableEntries; + const size_t size = totalSizeToAlloc(count); + ::operator delete(ptr, size); + } + /// The number of witness slots in a conformance to this protocol; /// in other words, the size of the table in words. unsigned getNumWitnesses() const {