Skip to content

Commit 7d42fe2

Browse files
authored
Deallocate resources for DacDbiArrayList with a matching deallocator (#58791)
Deleted InfoStoreForDbiNew as there were no users. Added DeleteDbiMemory to deal with destruction of items and proper usage of the corresponding allocator. However, using this custom new here across dll boundaries is risky as the T type will get its destructor called then the array list is destructed. The old implementation that used the CLR allocators didn't call the destructors on the inner elements (we had a potential leak, in practice it wasn't very noticeable - most objects are never deleted). After #55945, the standard array delete expression - as well as this change - call the destructor on every object. Currently, the instantiations of this type are all devoid of special destructors and are largely blittable structs, so this remains working as it was: - ICorDebugInfo::NativeVarInfo - GUID - FieldData - DebuggerIPCE_TypeArgData - DebuggerIPCE_ExpandedTypeData - DebuggerIPCE_BasicTypeData - DebuggerILToNativeMap - DacExceptionCallStackData - CordbType * - CORDB_ADDRESS - COR_SEGMENT - COR_MEMORY_RA
1 parent f7b441d commit 7d42fe2

File tree

4 files changed

+33
-10
lines changed

4 files changed

+33
-10
lines changed

src/coreclr/debug/daccess/dacdbiimpl.cpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ IDacDbiInterface::IAllocator * g_pAllocator = NULL;
7878
// return; // DBI will then free this memory.
7979
// }
8080
// ...
81-
// DeleteDbiMemory(p);
81+
// DeleteDbiMemory(p); // DeleteDbiMemory(p, len); if it was an array allocation.
8282
// }
8383
//
8484
// Be very careful when using this on classes since Dbi and DAC may be in
@@ -155,6 +155,25 @@ template<class T> void DeleteDbiMemory(T *p)
155155
g_pAllocator->Free((BYTE*) p);
156156
}
157157

158+
// Delete memory and invoke dtor for memory allocated with 'operator (forDbi) new[]'
159+
// There's an inherent risk here - where each element's destructor will get called within
160+
// the context of the DAC. If the destructor tries to use the CRT allocator logic expecting
161+
// to hit the DBI's, we could be in trouble. Those objects need to use an export allocator like this.
162+
template<class T> void DeleteDbiArrayMemory(T *p, int count)
163+
{
164+
if (p == NULL)
165+
{
166+
return;
167+
}
168+
169+
for (T *cur = p; cur < p + count; cur++)
170+
{
171+
cur->~T();
172+
}
173+
174+
_ASSERTE(g_pAllocator != NULL);
175+
g_pAllocator->Free((BYTE*) p);
176+
}
158177

159178
//---------------------------------------------------------------------------------------
160179
// Creates the DacDbiInterface object, used by Dbi.
@@ -818,12 +837,6 @@ SIZE_T DacDbiInterfaceImpl::GetArgCount(MethodDesc * pMD)
818837
return NumArguments;
819838
} //GetArgCount
820839

821-
// Allocator to pass to DebugInfoStores, allocating forDBI
822-
BYTE* InfoStoreForDbiNew(void * pData, size_t cBytes)
823-
{
824-
return new(forDbi) BYTE[cBytes];
825-
}
826-
827840
// Allocator to pass to the debug-info-stores...
828841
BYTE* InfoStoreNew(void * pData, size_t cBytes)
829842
{

src/coreclr/debug/di/rspriv.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,16 @@ struct MachineInfo
168168
USHORT m_usPort;
169169
};
170170

171+
#ifdef DACCESS_COMPILE
172+
#error This header cannot be used in the DAC
173+
#endif
174+
171175
extern forDbiWorker forDbi;
172176

173177
// for dbi we just default to new, but we need to have these defined for both dac and dbi
174178
inline void * operator new(size_t lenBytes, const forDbiWorker &)
175179
{
176-
void * result = new BYTE[lenBytes];
180+
void * result = new (nothrow) BYTE[lenBytes];
177181
if (result == NULL)
178182
{
179183
ThrowOutOfMemory();
@@ -183,7 +187,7 @@ inline void * operator new(size_t lenBytes, const forDbiWorker &)
183187

184188
inline void * operator new[](size_t lenBytes, const forDbiWorker &)
185189
{
186-
void * result = new BYTE[lenBytes];
190+
void * result = new (nothrow) BYTE[lenBytes];
187191
if (result == NULL)
188192
{
189193
ThrowOutOfMemory();
@@ -198,6 +202,11 @@ void DeleteDbiMemory(T *p)
198202
delete p;
199203
}
200204

205+
template<class T> inline
206+
void DeleteDbiArrayMemory(T *p, int)
207+
{
208+
delete[] p;
209+
}
201210

202211

203212
//---------------------------------------------------------------------------------------

src/coreclr/debug/inc/dacdbiinterface.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
// In the DBI implementation, this can directly call delete (assuming the IAllocator::Free
3030
// directly called new).
3131
template<class T> void DeleteDbiMemory(T *p);
32+
template<class T> void DeleteDbiArrayMemory(T *p, int count);
3233
// Need a class to serve as a tag that we can use to overload New/Delete.
3334
class forDbiWorker {};
3435
extern forDbiWorker forDbi;

src/coreclr/debug/inc/dacdbistructures.inl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ void DacDbiArrayList<T>::Dealloc()
7171

7272
if (m_pList != NULL)
7373
{
74-
delete [] m_pList;
74+
DeleteDbiArrayMemory(m_pList, m_nEntries);
7575
m_pList = NULL;
7676
}
7777
m_nEntries = 0;

0 commit comments

Comments
 (0)