You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
402 lines
13 KiB
402 lines
13 KiB
#if !defined(FUSION_INC_FUSIONHEAP_H_INCLUDED_)
|
|
#define FUSION_INC_FUSIONHEAP_H_INCLUDED_
|
|
|
|
#pragma once
|
|
|
|
#include "debmacro.h"
|
|
#include "SxsExceptionHandling.h"
|
|
#include "fusionunused.h"
|
|
#include "fusionlastwin32error.h"
|
|
|
|
#if !defined(FUSION_DISABLE_DEBUG_HEAP_ON_WIN98)
|
|
#if DBG
|
|
#if defined(FUSION_DEBUG_HEAP)
|
|
#undef FUSION_DEBUG_HEAP
|
|
#endif // defined(FUSION_DEBUG_HEAP)
|
|
#define FUSION_DEBUG_HEAP 1
|
|
#endif // DBG
|
|
#else
|
|
#undef FUSION_DEBUG_HEAP
|
|
#endif
|
|
|
|
//
|
|
// We allocate FUSION_ARRAY_PREFIX_LENGTH extra bytes at
|
|
// the beginning of array allocations to store the number of
|
|
// elements in the array.
|
|
//
|
|
|
|
#define FUSION_ARRAY_PREFIX_LENGTH (sizeof(void*)*2)
|
|
|
|
C_ASSERT(FUSION_ARRAY_PREFIX_LENGTH >= sizeof(SIZE_T));
|
|
|
|
EXTERN_C
|
|
BOOL
|
|
FusionpInitializeHeap(
|
|
HINSTANCE hInstance
|
|
);
|
|
|
|
EXTERN_C
|
|
VOID
|
|
FusionpUninitializeHeap();
|
|
|
|
// Unique type so that we can overload operator new and delete and not
|
|
// have ambiguity with the fact that HANDLE == PVOID.
|
|
|
|
typedef struct _FUSION_HEAP_HANDLE_FAKE_STRUCT *FUSION_HEAP_HANDLE;
|
|
|
|
EXTERN_C FUSION_HEAP_HANDLE g_hHeap;
|
|
#define FUSION_DEFAULT_PROCESS_HEAP() (g_hHeap)
|
|
|
|
#if FUSION_DEBUG_HEAP
|
|
|
|
EXTERN_C FUSION_HEAP_HANDLE g_hDebugInfoHeap;
|
|
EXTERN_C LONG g_FusionHeapAllocationCount;
|
|
EXTERN_C LONG g_FusionHeapAllocationToBreakOn;
|
|
|
|
#define FUSION_HEAP_ALLOCATION_FREED_WHEN_DLL_UNLOADED (0x00000001)
|
|
#define FUSION_HEAP_DO_NOT_REPORT_LEAKED_ALLOCATION (0x00000002)
|
|
|
|
typedef struct _FUSION_HEAP_ALLOCATION_TRACKER *PFUSION_HEAP_ALLOCATION_TRACKER;
|
|
|
|
#if defined(_WIN64)
|
|
#define FUSION_HEAP_ALIGNMENT 16 /* 2*sizeof(void*) but __declspec(align()) doesn't like that */
|
|
#else
|
|
#define FUSION_HEAP_ALIGNMENT 8 /* 2*sizeof(void*) but __declspec(align()) doesn't like that */
|
|
#endif
|
|
#define FUSION_HEAP_ALIGNMENT_MINUS_1 (FUSION_HEAP_ALIGNMENT - 1)
|
|
#define FUSION_HEAP_ROUND_SIZE(_x) (((_x) + FUSION_HEAP_ALIGNMENT_MINUS_1) & ~FUSION_HEAP_ALIGNMENT_MINUS_1)
|
|
|
|
C_ASSERT(FUSION_ARRAY_PREFIX_LENGTH >= FUSION_HEAP_ALIGNMENT);
|
|
C_ASSERT((FUSION_ARRAY_PREFIX_LENGTH % FUSION_HEAP_ALIGNMENT) == 0);
|
|
|
|
typedef struct DECLSPEC_ALIGN(FUSION_HEAP_ALIGNMENT) _FUSION_HEAP_PREFIX
|
|
{
|
|
union
|
|
{
|
|
PFUSION_HEAP_ALLOCATION_TRACKER Tracker;
|
|
void* InterlockedAlignment[2];
|
|
};
|
|
} FUSION_HEAP_PREFIX, *PFUSION_HEAP_PREFIX;
|
|
|
|
typedef struct DECLSPEC_ALIGN(FUSION_HEAP_ALIGNMENT) _FUSION_HEAP_ALLOCATION_TRACKER
|
|
{
|
|
PFUSION_HEAP_PREFIX Prefix;
|
|
FUSION_HEAP_HANDLE Heap;
|
|
size_t AllocationSize;
|
|
size_t RequestedSize;
|
|
PCSTR FileName;
|
|
PCSTR Expression;
|
|
LONG SequenceNumber;
|
|
INT Line;
|
|
DWORD Flags;
|
|
// We have to track this here because someone could change the global setting while the dll is running
|
|
PUCHAR PostAllocPoisonArea;
|
|
UCHAR PostAllocPoisonChar;
|
|
ULONG PostAllocPoisonBytes;
|
|
#if FUSION_ENABLE_FROZEN_STACK
|
|
PVOID pvFrozenStack;
|
|
#endif
|
|
} FUSION_HEAP_ALLOCATION_TRACKER, *PFUSION_HEAP_ALLOCATION_TRACKER;
|
|
|
|
PVOID
|
|
FusionpDbgHeapAlloc(
|
|
FUSION_HEAP_HANDLE hHeap,
|
|
DWORD dwHeapAllocFlags,
|
|
SIZE_T cb,
|
|
PCSTR pszFile,
|
|
INT nLine,
|
|
PCSTR pszExpression,
|
|
DWORD dwFusionFlags
|
|
);
|
|
|
|
PVOID
|
|
FusionpDbgHeapReAlloc(
|
|
FUSION_HEAP_HANDLE hHeap,
|
|
DWORD dwHeapReAllocFlags,
|
|
PVOID lpMem,
|
|
SIZE_T cb,
|
|
PCSTR pszFile,
|
|
INT nLine,
|
|
PCSTR pszExpression,
|
|
DWORD dwFusionFlags
|
|
);
|
|
|
|
EXTERN_C
|
|
BOOL
|
|
FusionpDbgHeapFree(
|
|
FUSION_HEAP_HANDLE hHeap,
|
|
DWORD dwHeapFreeFlags,
|
|
PVOID lpMem
|
|
);
|
|
|
|
EXTERN_C
|
|
VOID
|
|
FusionpDeallocateTracker(
|
|
PFUSION_HEAP_PREFIX p
|
|
);
|
|
|
|
EXTERN_C
|
|
BOOL
|
|
FusionpEnableLeakTracking(
|
|
BOOL Enable);
|
|
|
|
EXTERN_C
|
|
VOID *
|
|
FusionpGetFakeVTbl();
|
|
|
|
|
|
EXTERN_C
|
|
VOID
|
|
FusionpDontTrackBlk(
|
|
VOID *pv
|
|
);
|
|
|
|
#define FusionpHeapAllocEx(_hHeap, _dwFlags, _nBytes, _szExpr, _szFile, _nLine, _dwFusionHeapFlags) FusionpDbgHeapAlloc((_hHeap), (_dwFlags), (_nBytes), (_szFile), (_nLine), (_szExpr), (_dwFusionHeapFlags))
|
|
#define FusionpHeapReAllocEx(_hHeap, _dwFlags, _lpMem, _nBytes, _szExpr, _szFile, _nLine, _dwFusionHeapFlags) FusionpDbgHeapReAlloc((_hHeap), (_dwFlags), (_lpMem), (_nBytes), (_szFile), (_nLine), (_szExpr), (_dwFusionHeapFlags))
|
|
#define FusionpHeapFreeEx(_hHeap, _dwFlags, _lpMem) FusionpDbgHeapFree((_hHeap), (_dwFlags), (_lpMem))
|
|
|
|
#define FusionpHeapAlloc(_hHeap, _dwFlags, _nBytes) FusionpHeapAllocEx((_hHeap), (_dwFlags), (_nBytes), NULL, NULL, 0, 0)
|
|
#define FusionpHeapReAlloc(_hHeap, _dwFlags, _lpMem, _nBytes) FusionpHeapReAllocEx((_hHeap), (_dwFlags), (_lpMem), (_nBytes), NULL, NULL, 0, 0)
|
|
#define FusionpHeapFree(_hHeap, _dwFlags, _lpMem) FusionpHeapFreeEx((_hHeap), (_dwFlags), (_lpMem))
|
|
|
|
#define FUSION_HEAP_DISABLE_LEAK_TRACKING() do { ::FusionpEnableLeakTracking(FALSE); } while (0)
|
|
#define FUSION_HEAP_ENABLE_LEAK_TRACKING() do { ::FusionpEnableLeakTracking(TRUE); } while (0)
|
|
|
|
EXTERN_C
|
|
VOID
|
|
FusionpDumpHeap(
|
|
PCWSTR PerLinePrefix
|
|
);
|
|
|
|
#else // FUSION_DEBUG_HEAP
|
|
|
|
LPVOID
|
|
WINAPI
|
|
FusionpHeapAlloc(
|
|
IN HANDLE hHeap,
|
|
IN DWORD dwFlags,
|
|
IN SIZE_T dwBytes
|
|
);
|
|
|
|
LPVOID
|
|
WINAPI
|
|
FusionpHeapReAlloc(
|
|
IN HANDLE hHeap,
|
|
IN DWORD dwFlags,
|
|
IN LPVOID lpMem,
|
|
IN SIZE_T dwBytes
|
|
);
|
|
|
|
#define FusionpHeapFree HeapFree
|
|
|
|
#define FusionpHeapAllocEx(_hHeap, _dwFlags, _nBytes, _szExpr, _szFile, _nLine, _dwFusionHeapFlags) HeapAlloc((_hHeap), (_dwFlags), (_nBytes))
|
|
#define FusionpHeapReAllocEx(_hHeap, _dwFlags, _lpMem, _nBytes, _szExpr, _szFile, _nLine, _dwFusionHeapFlags) HeapReAlloc((_hHeap), (_dwFlags), (_lpMem), (_nBytes))
|
|
#define FusionpHeapFreeEx(_hHeap, _dwFlags, _lpMem) HeapFree((_hHeap), (_dwFlags), (_lpMem))
|
|
|
|
#define FUSION_HEAP_DISABLE_LEAK_TRACKING()
|
|
#define FUSION_HEAP_ENABLE_LEAK_TRACKING()
|
|
|
|
#endif // FUSION_DEBUG_HEAP
|
|
|
|
template <typename T> class CAllocator
|
|
{
|
|
public:
|
|
static inline T *AllocateArray(FUSION_HEAP_HANDLE hHeap, PCSTR szFile, int nLine, PCSTR szExpression, DWORD dwWin32HeapFlags, SIZE_T cElements, DWORD dwFusionHeapFlags)
|
|
{
|
|
T *prgtResult = NULL;
|
|
PVOID pv = ::FusionpHeapAllocEx(hHeap, dwWin32HeapFlags, FUSION_ARRAY_PREFIX_LENGTH + (sizeof(T) * cElements), szExpression, szFile, nLine, dwFusionHeapFlags);
|
|
if (pv != NULL)
|
|
{
|
|
SIZE_T i;
|
|
T *prgt = (T *) (((ULONG_PTR) pv) + FUSION_ARRAY_PREFIX_LENGTH);
|
|
|
|
*((SIZE_T *) pv) = cElements;
|
|
|
|
// Initialize each element by calling its constructing via the "normal" placement new.
|
|
for (i=0; i<cElements; i++)
|
|
{
|
|
T *pt = new(&prgt[i]) T;
|
|
ASSERT_NTC(pt == &prgt[i]);
|
|
RETAIL_UNUSED(pt);
|
|
}
|
|
|
|
prgtResult = prgt;
|
|
}
|
|
|
|
return prgtResult;
|
|
}
|
|
|
|
static inline T *AllocateSingleton(FUSION_HEAP_HANDLE hHeap, PCSTR szFile, int nLine, PCSTR szExpression, DWORD dwWin32HeapFlags, DWORD dwFusionHeapFlags)
|
|
{
|
|
T *ptResult = NULL;
|
|
PVOID pv = ::FusionpHeapAllocEx(hHeap, dwWin32HeapFlags, sizeof(T), szExpression, szFile, nLine, dwFusionHeapFlags);
|
|
if (pv != NULL)
|
|
{
|
|
// Initialize calling its constructing via the "normal" placement new.
|
|
T *pt = new(pv) T;
|
|
ASSERT_NTC(pt == pv);
|
|
ptResult = pt;
|
|
}
|
|
|
|
return ptResult;
|
|
}
|
|
|
|
static inline VOID DeallocateArray(FUSION_HEAP_HANDLE hHeap, DWORD dwWin32HeapFlags, T *prgt)
|
|
{
|
|
const DWORD _dwLastError = ::FusionpGetLastWin32Error();
|
|
|
|
if (prgt != NULL)
|
|
{
|
|
// This thing had better be aligned...
|
|
|
|
ASSERT_NTC((((ULONG_PTR) prgt) % FUSION_HEAP_ALIGNMENT) == 0);
|
|
|
|
SIZE_T *pcElements = (SIZE_T *) (((ULONG_PTR) prgt) - FUSION_ARRAY_PREFIX_LENGTH);
|
|
SIZE_T i;
|
|
SIZE_T cElements = *pcElements;
|
|
|
|
for (i=0; i<cElements; i++)
|
|
prgt[i].~T();
|
|
|
|
::FusionpHeapFree(hHeap, dwWin32HeapFlags, pcElements);
|
|
}
|
|
|
|
::FusionpSetLastWin32Error( _dwLastError );
|
|
}
|
|
|
|
static inline VOID DeallocateSingleton(FUSION_HEAP_HANDLE hHeap, DWORD dwWin32HeapFlags, T *pt)
|
|
{
|
|
const DWORD _dwLastError = ::FusionpGetLastWin32Error();
|
|
|
|
if (pt != NULL)
|
|
{
|
|
pt->~T();
|
|
::FusionpHeapFree(hHeap, dwWin32HeapFlags, pt);
|
|
}
|
|
|
|
::FusionpSetLastWin32Error( _dwLastError );
|
|
}
|
|
};
|
|
|
|
template <typename T> inline void FusionpAllocateSingletonFromPrivateHeap(FUSION_HEAP_HANDLE hHeap, DWORD dwWin32HeapFlags, T *ptUnused, PCSTR szFile, int nLine, PCSTR szTypeName) { (ptUnused); return CAllocator<T>::AllocateSingleton(hHeap, szFile, nLine, szTypeName, 0, 0); }
|
|
template <typename T> inline void FusionpAllocateArrayFromPrivateHeap(FUSION_HEAP_HANDLE hHeap, DWORD dwWin32HeapFlags, SIZE_T cElements, T *ptUnused, PCSTR szFile, int nLine, PCSTR szTypeName) { (ptUnused); return CAllocator<T>::AllocateArray(hHeap, szFile, nLine, szTypeName, 0, cElements, 0); }
|
|
template <typename T> inline void FusionpDeleteArrayFromPrivateHeap(FUSION_HEAP_HANDLE hHeap, DWORD dwWin32HeapFlags, T *prgt) { CAllocator<T>::DeallocateArray(hHeap, dwWin32HeapFlags, prgt); }
|
|
|
|
template <typename T> inline void FusionpDeleteSingletonFromPrivateHeap(FUSION_HEAP_HANDLE hHeap, DWORD dwWin32HeapFlags, T *pt) { CAllocator<T>::DeallocateSingleton(hHeap, dwWin32HeapFlags, pt); }
|
|
|
|
#define FUSION_NEW_SINGLETON(_type) (new(__FILE__, __LINE__, #_type) _type)
|
|
#define FUSION_NEW_ARRAY(_type, _n) (new _type[_n])
|
|
|
|
// #define FUSION_DELETE_SINGLETON_(_heap, _ptr) do { ::FusionpDeleteSingletonFromPrivateHeap((_heap), 0, (_ptr)); } while (0)
|
|
// #define FUSION_DELETE_ARRAY_(_heap, _ptr) do { ::FusionpDeleteArrayFromPrivateHeap((_heap), 0, _ptr); } while (0)
|
|
|
|
#define FUSION_DELETE_SINGLETON(_ptr) do { delete (_ptr); } while (0) /* FUSION_DELETE_SINGLETON_(FUSION_DEFAULT_PROCESS_HEAP(), _ptr) */
|
|
#define FUSION_DELETE_ARRAY(_ptr) do { delete [](_ptr); } while (0) /* FUSION_DELETE_ARRAY_(FUSION_DEFAULT_PROCESS_HEAP(), _ptr) */
|
|
|
|
#define FUSION_RAW_ALLOC_(_heap, _cb, _typeTag) (::FusionpHeapAllocEx((_heap), 0, (_cb), #_typeTag, __FILE__, __LINE__, 0))
|
|
#define FUSION_RAW_DEALLOC_(_heap, _ptr) (::FusionpHeapFree((_heap), 0, (_ptr)))
|
|
|
|
#define FUSION_RAW_ALLOC(_cb, _typeTag) FUSION_RAW_ALLOC_(FUSION_DEFAULT_PROCESS_HEAP(), _cb, _typeTag)
|
|
#define FUSION_RAW_DEALLOC(_ptr) FUSION_RAW_DEALLOC_(FUSION_DEFAULT_PROCESS_HEAP(), _ptr)
|
|
|
|
#define NEW(_type) FUSION_NEW_SINGLETON(_type)
|
|
#define NEW_SINGLETON_(_heap, _type) FUSION_NEW_SINGLETON_(_heap, _type)
|
|
#define NEW_ARRAY_(_heap, _type, _n) FUSION_NEW_ARRAY_(_heap, _type, _n)
|
|
|
|
#define DELETE_ARRAY(_ptr) FUSION_DELETE_ARRAY(_ptr)
|
|
#define DELETE_ARRAY_(_heap, _ptr) FUSION_DELETE_ARRAY_(_heap, _ptr)
|
|
|
|
#define DELETE_SINGLETON(_ptr) FUSION_DELETE_SINGLETON(_ptr)
|
|
#define DELETE_SINGLETON_(_heap, _ptr) FUSION_DELETE_SINGLETON_(_heap, _ptr)
|
|
|
|
#if defined(__cplusplus)
|
|
|
|
#if FUSION_ENABLE_UNWRAPPED_NEW
|
|
|
|
inline void * __cdecl operator new(size_t cb)
|
|
{
|
|
return ::FusionpHeapAllocEx(FUSION_DEFAULT_PROCESS_HEAP(), 0, cb, NULL, NULL, NULL, 0);
|
|
}
|
|
|
|
inline void * __cdecl operator new(size_t cb, PCSTR pszFile, int nLine, PCSTR pszTypeName)
|
|
{
|
|
return ::FusionpHeapAllocEx(FUSION_DEFAULT_PROCESS_HEAP(), 0, cb, pszTypeName, pszFile, nLine, 0);
|
|
}
|
|
|
|
#else // FUSION_ENABLE_UNWRAPPED_NEW
|
|
|
|
EXTERN_C PVOID SomebodyUsedUnwrappedOperatorNew(size_t cb);
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4211)
|
|
|
|
static inline void * __cdecl operator new(size_t cb)
|
|
{
|
|
// Call a bogus function so that we'll get a link error. DO NOT IMPLEMENT THIS
|
|
// FUNCTION EVER! It's referenced here to generate build errors rather than runtime ones.
|
|
return ::SomebodyUsedUnwrappedOperatorNew(cb);
|
|
}
|
|
|
|
#pragma warning(pop)
|
|
|
|
#endif // FUSION_ENABLE_UNWRAPPED_NEW
|
|
|
|
#if FUSION_ENABLE_UNWRAPPED_DELETE
|
|
|
|
inline void __cdecl operator delete(void *pv)
|
|
{
|
|
if (pv != NULL)
|
|
::FusionpHeapFreeEx(FUSION_DEFAULT_PROCESS_HEAP(), 0, pv);
|
|
}
|
|
|
|
inline void __cdecl operator delete(void *pv, PCSTR pszFile, int nLine, PCSTR pszTypeName)
|
|
{
|
|
if (pv != NULL)
|
|
::FusionpHeapFreeEx(FUSION_DEFAULT_PROCESS_HEAP(), 0, pv);
|
|
}
|
|
|
|
#else
|
|
|
|
EXTERN_C VOID SomebodyUsedUnwrappedOperatorDelete(void *pv);
|
|
|
|
static void __cdecl operator delete(void *pv)
|
|
{
|
|
return ::SomebodyUsedUnwrappedOperatorDelete(pv);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifndef __PLACEMENT_NEW_INLINE
|
|
#define __PLACEMENT_NEW_INLINE
|
|
inline void *__cdecl operator new(size_t, void *P) { return (P); }
|
|
#if _MSC_VER >= 1200
|
|
inline void __cdecl operator delete(void *, void *) { return; }
|
|
#endif
|
|
#endif
|
|
|
|
inline void * __cdecl operator new(size_t cb, FUSION_HEAP_HANDLE hHeap, PCSTR pszFile, INT nLine, PCSTR pszExpression, DWORD dwFusionHeapFlags)
|
|
{
|
|
ASSERT_NTC(hHeap != 0);
|
|
return ::FusionpHeapAllocEx(hHeap, 0, cb, pszExpression, pszFile, nLine, dwFusionHeapFlags);
|
|
}
|
|
|
|
//
|
|
// error C4291: 'void *operator new(size_t,FUSION_HEAP_HANDLE,const PCSTR,INT,const PCSTR,DWORD)'
|
|
// : no matching operator delete found; memory will not be freed if initialization throws an exception
|
|
//
|
|
inline void __cdecl
|
|
operator delete(
|
|
void* p,
|
|
FUSION_HEAP_HANDLE hHeap,
|
|
PCSTR /* pszFile */,
|
|
INT /* nLine */,
|
|
PCSTR /* pszExpression */,
|
|
DWORD /* dwFusionHeapFlags */)
|
|
{
|
|
ASSERT_NTC(hHeap != 0);
|
|
FusionpDeleteSingletonFromPrivateHeap(hHeap, 0, p);
|
|
}
|
|
|
|
#endif // defined(__cplusplus)
|
|
|
|
#endif
|