Source code of Windows XP (NT5)
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.

380 lines
12 KiB

  1. #if !defined(FUSION_INC_FUSIONHEAP_H_INCLUDED_)
  2. #define FUSION_INC_FUSIONHEAP_H_INCLUDED_
  3. #pragma once
  4. #include "debmacro.h"
  5. #include "SxsExceptionHandling.h"
  6. #include "fusionunused.h"
  7. #include "fusionlastwin32error.h"
  8. #if DBG
  9. #if defined(FUSION_DEBUG_HEAP)
  10. #undef FUSION_DEBUG_HEAP
  11. #endif // defined(FUSION_DEBUG_HEAP)
  12. #define FUSION_DEBUG_HEAP 1
  13. #endif // DBG
  14. //
  15. // We allocate FUSION_ARRAY_PREFIX_LENGTH extra bytes at
  16. // the beginning of array allocations to store the number of
  17. // elements in the array.
  18. //
  19. #define FUSION_ARRAY_PREFIX_LENGTH (sizeof(void*)*2)
  20. C_ASSERT(FUSION_ARRAY_PREFIX_LENGTH >= sizeof(SIZE_T));
  21. EXTERN_C
  22. BOOL
  23. FusionpInitializeHeap(
  24. HINSTANCE hInstance
  25. );
  26. EXTERN_C
  27. VOID
  28. FusionpUninitializeHeap();
  29. // Unique type so that we can overload operator new and delete and not
  30. // have ambiguity with the fact that HANDLE == PVOID.
  31. typedef struct _FUSION_HEAP_HANDLE_FAKE_STRUCT *FUSION_HEAP_HANDLE;
  32. EXTERN_C FUSION_HEAP_HANDLE g_hHeap;
  33. #define FUSION_DEFAULT_PROCESS_HEAP() (g_hHeap)
  34. #if FUSION_DEBUG_HEAP
  35. EXTERN_C FUSION_HEAP_HANDLE g_hDebugInfoHeap;
  36. EXTERN_C LONG g_FusionHeapAllocationCount;
  37. EXTERN_C LONG g_FusionHeapAllocationToBreakOn;
  38. #define FUSION_HEAP_ALLOCATION_FREED_WHEN_DLL_UNLOADED (0x00000001)
  39. #define FUSION_HEAP_DO_NOT_REPORT_LEAKED_ALLOCATION (0x00000002)
  40. typedef struct _FUSION_HEAP_ALLOCATION_TRACKER *PFUSION_HEAP_ALLOCATION_TRACKER;
  41. #if defined(_WIN64)
  42. #define FUSION_HEAP_ALIGNMENT 16 /* 2*sizeof(void*) but __declspec(align()) doesn't like that */
  43. #else
  44. #define FUSION_HEAP_ALIGNMENT 8 /* 2*sizeof(void*) but __declspec(align()) doesn't like that */
  45. #endif
  46. #define FUSION_HEAP_ALIGNMENT_MINUS_1 (FUSION_HEAP_ALIGNMENT - 1)
  47. #define FUSION_HEAP_ROUND_SIZE(_x) (((_x) + FUSION_HEAP_ALIGNMENT_MINUS_1) & ~FUSION_HEAP_ALIGNMENT_MINUS_1)
  48. typedef struct DECLSPEC_ALIGN(FUSION_HEAP_ALIGNMENT) _FUSION_HEAP_PREFIX
  49. {
  50. union
  51. {
  52. PFUSION_HEAP_ALLOCATION_TRACKER Tracker;
  53. void* InterlockedAlignment[2];
  54. };
  55. } FUSION_HEAP_PREFIX, *PFUSION_HEAP_PREFIX;
  56. typedef struct DECLSPEC_ALIGN(FUSION_HEAP_ALIGNMENT) _FUSION_HEAP_ALLOCATION_TRACKER
  57. {
  58. PFUSION_HEAP_PREFIX Prefix;
  59. FUSION_HEAP_HANDLE Heap;
  60. size_t AllocationSize;
  61. size_t RequestedSize;
  62. PCSTR FileName;
  63. PCSTR Expression;
  64. LONG SequenceNumber;
  65. INT Line;
  66. DWORD Flags;
  67. // We have to track this here because someone could change the global setting while the dll is running
  68. PUCHAR PostAllocPoisonArea;
  69. UCHAR PostAllocPoisonChar;
  70. ULONG PostAllocPoisonBytes;
  71. #if FUSION_ENABLE_FROZEN_STACK
  72. PVOID pvFrozenStack;
  73. #endif
  74. } FUSION_HEAP_ALLOCATION_TRACKER, *PFUSION_HEAP_ALLOCATION_TRACKER;
  75. PVOID
  76. FusionpDbgHeapAlloc(
  77. FUSION_HEAP_HANDLE hHeap,
  78. DWORD dwHeapAllocFlags,
  79. SIZE_T cb,
  80. PCSTR pszFile,
  81. INT nLine,
  82. PCSTR pszExpression,
  83. DWORD dwFusionFlags
  84. );
  85. PVOID
  86. FusionpDbgHeapReAlloc(
  87. FUSION_HEAP_HANDLE hHeap,
  88. DWORD dwHeapReAllocFlags,
  89. PVOID lpMem,
  90. SIZE_T cb,
  91. PCSTR pszFile,
  92. INT nLine,
  93. PCSTR pszExpression,
  94. DWORD dwFusionFlags
  95. );
  96. EXTERN_C
  97. BOOL
  98. FusionpDbgHeapFree(
  99. FUSION_HEAP_HANDLE hHeap,
  100. DWORD dwHeapFreeFlags,
  101. PVOID lpMem
  102. );
  103. EXTERN_C
  104. VOID
  105. FusionpDeallocateTracker(
  106. PFUSION_HEAP_PREFIX p
  107. );
  108. EXTERN_C
  109. BOOL
  110. FusionpEnableLeakTracking(
  111. BOOL Enable);
  112. EXTERN_C
  113. VOID *
  114. FusionpGetFakeVTbl();
  115. EXTERN_C
  116. VOID
  117. FusionpDontTrackBlk(
  118. VOID *pv
  119. );
  120. #define FusionpHeapAllocEx(_hHeap, _dwFlags, _nBytes, _szExpr, _szFile, _nLine, _dwFusionHeapFlags) FusionpDbgHeapAlloc((_hHeap), (_dwFlags), (_nBytes), (_szFile), (_nLine), (_szExpr), (_dwFusionHeapFlags))
  121. #define FusionpHeapReAllocEx(_hHeap, _dwFlags, _lpMem, _nBytes, _szExpr, _szFile, _nLine, _dwFusionHeapFlags) FusionpDbgHeapReAlloc((_hHeap), (_dwFlags), (_lpMem), (_nBytes), (_szFile), (_nLine), (_szExpr), (_dwFusionHeapFlags))
  122. #define FusionpHeapFreeEx(_hHeap, _dwFlags, _lpMem) FusionpDbgHeapFree((_hHeap), (_dwFlags), (_lpMem))
  123. #define FusionpHeapAlloc(_hHeap, _dwFlags, _nBytes) FusionpHeapAllocEx((_hHeap), (_dwFlags), (_nBytes), NULL, NULL, 0, 0)
  124. #define FusionpHeapReAlloc(_hHeap, _dwFlags, _lpMem, _nBytes) FusionpHeapReAllocEx((_hHeap), (_dwFlags), (_lpMem), (_nBytes), NULL, NULL, 0, 0)
  125. #define FusionpHeapFree(_hHeap, _dwFlags, _lpMem) FusionpHeapFreeEx((_hHeap), (_dwFlags), (_lpMem))
  126. #define FUSION_HEAP_DISABLE_LEAK_TRACKING() do { ::FusionpEnableLeakTracking(FALSE); } while (0)
  127. #define FUSION_HEAP_ENABLE_LEAK_TRACKING() do { ::FusionpEnableLeakTracking(TRUE); } while (0)
  128. EXTERN_C
  129. VOID
  130. FusionpDumpHeap(
  131. PCWSTR PerLinePrefix
  132. );
  133. #else // FUSION_DEBUG_HEAP
  134. #define FusionpHeapAlloc HeapAlloc
  135. #define FusionpHeapReAlloc HeapReAlloc
  136. #define FusionpHeapFree HeapFree
  137. #define FusionpHeapAllocEx(_hHeap, _dwFlags, _nBytes, _szExpr, _szFile, _nLine, _dwFusionHeapFlags) HeapAlloc((_hHeap), (_dwFlags), (_nBytes))
  138. #define FusionpHeapReAllocEx(_hHeap, _dwFlags, _lpMem, _nBytes, _szExpr, _szFile, _nLine, _dwFusionHeapFlags) HeapReAlloc((_hHeap), (_dwFlags), (_lpMem), (_nBytes))
  139. #define FusionpHeapFreeEx(_hHeap, _dwFlags, _lpMem) HeapFree((_hHeap), (_dwFlags), (_lpMem))
  140. #define FUSION_HEAP_DISABLE_LEAK_TRACKING()
  141. #define FUSION_HEAP_ENABLE_LEAK_TRACKING()
  142. #endif // FUSION_DEBUG_HEAP
  143. template <typename T> class CAllocator
  144. {
  145. public:
  146. static inline T *AllocateArray(FUSION_HEAP_HANDLE hHeap, PCSTR szFile, int nLine, PCSTR szExpression, DWORD dwWin32HeapFlags, SIZE_T cElements, DWORD dwFusionHeapFlags)
  147. {
  148. T *prgtResult = NULL;
  149. PVOID pv = ::FusionpHeapAllocEx(hHeap, dwWin32HeapFlags, FUSION_ARRAY_PREFIX_LENGTH + (sizeof(T) * cElements), szExpression, szFile, nLine, dwFusionHeapFlags);
  150. if (pv != NULL)
  151. {
  152. SIZE_T i;
  153. T *prgt = (T *) (((ULONG_PTR) pv) + FUSION_ARRAY_PREFIX_LENGTH);
  154. *((SIZE_T *) pv) = cElements;
  155. // Initialize each element by calling its constructing via the "normal" placement new.
  156. for (i=0; i<cElements; i++)
  157. {
  158. T *pt = new(&prgt[i]) T;
  159. ASSERT_NTC(pt == &prgt[i]);
  160. RETAIL_UNUSED(pt);
  161. }
  162. prgtResult = prgt;
  163. }
  164. return prgtResult;
  165. }
  166. static inline T *AllocateSingleton(FUSION_HEAP_HANDLE hHeap, PCSTR szFile, int nLine, PCSTR szExpression, DWORD dwWin32HeapFlags, DWORD dwFusionHeapFlags)
  167. {
  168. T *ptResult = NULL;
  169. PVOID pv = ::FusionpHeapAllocEx(hHeap, dwWin32HeapFlags, sizeof(T), szExpression, szFile, nLine, dwFusionHeapFlags);
  170. if (pv != NULL)
  171. {
  172. // Initialize calling its constructing via the "normal" placement new.
  173. T *pt = new(pv) T;
  174. ASSERT_NTC(pt == pv);
  175. ptResult = pt;
  176. }
  177. return ptResult;
  178. }
  179. static inline VOID DeallocateArray(FUSION_HEAP_HANDLE hHeap, DWORD dwWin32HeapFlags, T *prgt)
  180. {
  181. const DWORD _dwLastError = ::FusionpGetLastWin32Error();
  182. if (prgt != NULL)
  183. {
  184. // This thing had better be aligned...
  185. ASSERT_NTC(
  186. (((ULONG_PTR) prgt) & 0x7) == 0);
  187. SIZE_T *pcElements = (SIZE_T *) (((ULONG_PTR) prgt) - FUSION_ARRAY_PREFIX_LENGTH);
  188. SIZE_T i;
  189. SIZE_T cElements = *pcElements;
  190. for (i=0; i<cElements; i++)
  191. prgt[i].~T();
  192. ::FusionpHeapFree(hHeap, dwWin32HeapFlags, pcElements);
  193. }
  194. ::FusionpSetLastWin32Error( _dwLastError );
  195. }
  196. static inline VOID DeallocateSingleton(FUSION_HEAP_HANDLE hHeap, DWORD dwWin32HeapFlags, T *pt)
  197. {
  198. const DWORD _dwLastError = ::FusionpGetLastWin32Error();
  199. if (pt != NULL)
  200. {
  201. pt->~T();
  202. ::FusionpHeapFree(hHeap, dwWin32HeapFlags, pt);
  203. }
  204. ::FusionpSetLastWin32Error( _dwLastError );
  205. }
  206. };
  207. 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); }
  208. 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); }
  209. template <typename T> inline void FusionpDeleteArrayFromPrivateHeap(FUSION_HEAP_HANDLE hHeap, DWORD dwWin32HeapFlags, T *prgt) { CAllocator<T>::DeallocateArray(hHeap, dwWin32HeapFlags, prgt); }
  210. template <typename T> inline void FusionpDeleteSingletonFromPrivateHeap(FUSION_HEAP_HANDLE hHeap, DWORD dwWin32HeapFlags, T *pt) { CAllocator<T>::DeallocateSingleton(hHeap, dwWin32HeapFlags, pt); }
  211. #define FUSION_NEW_SINGLETON(_type) (new(__FILE__, __LINE__, #_type) _type)
  212. #define FUSION_NEW_ARRAY(_type, _n) (new _type[_n])
  213. // #define FUSION_DELETE_SINGLETON_(_heap, _ptr) do { ::FusionpDeleteSingletonFromPrivateHeap((_heap), 0, (_ptr)); } while (0)
  214. // #define FUSION_DELETE_ARRAY_(_heap, _ptr) do { ::FusionpDeleteArrayFromPrivateHeap((_heap), 0, _ptr); } while (0)
  215. #define FUSION_DELETE_SINGLETON(_ptr) do { delete (_ptr); } while (0) /* FUSION_DELETE_SINGLETON_(FUSION_DEFAULT_PROCESS_HEAP(), _ptr) */
  216. #define FUSION_DELETE_ARRAY(_ptr) do { delete [](_ptr); } while (0) /* FUSION_DELETE_ARRAY_(FUSION_DEFAULT_PROCESS_HEAP(), _ptr) */
  217. #define FUSION_RAW_ALLOC_(_heap, _cb, _typeTag) (::FusionpHeapAllocEx((_heap), 0, (_cb), #_typeTag, __FILE__, __LINE__, 0))
  218. #define FUSION_RAW_DEALLOC_(_heap, _ptr) (::FusionpHeapFree((_heap), 0, (_ptr)))
  219. #define FUSION_RAW_ALLOC(_cb, _typeTag) FUSION_RAW_ALLOC_(FUSION_DEFAULT_PROCESS_HEAP(), _cb, _typeTag)
  220. #define FUSION_RAW_DEALLOC(_ptr) FUSION_RAW_DEALLOC_(FUSION_DEFAULT_PROCESS_HEAP(), _ptr)
  221. #define NEW(_type) FUSION_NEW_SINGLETON(_type)
  222. #define NEW_SINGLETON_(_heap, _type) FUSION_NEW_SINGLETON_(_heap, _type)
  223. #define NEW_ARRAY_(_heap, _type, _n) FUSION_NEW_ARRAY_(_heap, _type, _n)
  224. #define DELETE_ARRAY(_ptr) FUSION_DELETE_ARRAY(_ptr)
  225. #define DELETE_ARRAY_(_heap, _ptr) FUSION_DELETE_ARRAY_(_heap, _ptr)
  226. #define DELETE_SINGLETON(_ptr) FUSION_DELETE_SINGLETON(_ptr)
  227. #define DELETE_SINGLETON_(_heap, _ptr) FUSION_DELETE_SINGLETON_(_heap, _ptr)
  228. #if defined(__cplusplus)
  229. #if FUSION_ENABLE_UNWRAPPED_NEW
  230. inline void * __cdecl operator new(size_t cb)
  231. {
  232. return ::FusionpHeapAllocEx(FUSION_DEFAULT_PROCESS_HEAP(), 0, cb, NULL, NULL, NULL, 0);
  233. }
  234. inline void * __cdecl operator new(size_t cb, PCSTR pszFile, int nLine, PCSTR pszTypeName)
  235. {
  236. return ::FusionpHeapAllocEx(FUSION_DEFAULT_PROCESS_HEAP(), 0, cb, pszTypeName, pszFile, nLine, 0);
  237. }
  238. #else // FUSION_ENABLE_UNWRAPPED_NEW
  239. EXTERN_C PVOID SomebodyUsedUnwrappedOperatorNew(size_t cb);
  240. #pragma warning(push)
  241. #pragma warning(disable: 4211)
  242. static inline void * __cdecl operator new(size_t cb)
  243. {
  244. // Call a bogus function so that we'll get a link error. DO NOT IMPLEMENT THIS
  245. // FUNCTION EVER! It's referenced here to generate build errors rather than runtime ones.
  246. return ::SomebodyUsedUnwrappedOperatorNew(cb);
  247. }
  248. #pragma warning(pop)
  249. #endif // FUSION_ENABLE_UNWRAPPED_NEW
  250. #if FUSION_ENABLE_UNWRAPPED_DELETE
  251. inline void __cdecl operator delete(void *pv)
  252. {
  253. if (pv != NULL)
  254. ::FusionpHeapFreeEx(FUSION_DEFAULT_PROCESS_HEAP(), 0, pv);
  255. }
  256. inline void __cdecl operator delete(void *pv, PCSTR pszFile, int nLine, PCSTR pszTypeName)
  257. {
  258. if (pv != NULL)
  259. ::FusionpHeapFreeEx(FUSION_DEFAULT_PROCESS_HEAP(), 0, pv);
  260. }
  261. #else
  262. EXTERN_C VOID SomebodyUsedUnwrappedOperatorDelete(void *pv);
  263. static void __cdecl operator delete(void *pv)
  264. {
  265. return ::SomebodyUsedUnwrappedOperatorDelete(pv);
  266. }
  267. #endif
  268. #ifndef __PLACEMENT_NEW_INLINE
  269. #define __PLACEMENT_NEW_INLINE
  270. inline void *__cdecl operator new(size_t, void *P) { return (P); }
  271. #if _MSC_VER >= 1200
  272. inline void __cdecl operator delete(void *, void *) { return; }
  273. #endif
  274. #endif
  275. inline void * __cdecl operator new(size_t cb, FUSION_HEAP_HANDLE hHeap, PCSTR pszFile, INT nLine, PCSTR pszExpression, DWORD dwFusionHeapFlags)
  276. {
  277. ASSERT_NTC(hHeap != 0);
  278. return ::FusionpHeapAllocEx(hHeap, 0, cb, pszExpression, pszFile, nLine, dwFusionHeapFlags);
  279. }
  280. //
  281. // error C4291: 'void *operator new(size_t,FUSION_HEAP_HANDLE,const PCSTR,INT,const PCSTR,DWORD)'
  282. // : no matching operator delete found; memory will not be freed if initialization throws an exception
  283. //
  284. inline void __cdecl
  285. operator delete(
  286. void* p,
  287. FUSION_HEAP_HANDLE hHeap,
  288. PCSTR /* pszFile */,
  289. INT /* nLine */,
  290. PCSTR /* pszExpression */,
  291. DWORD /* dwFusionHeapFlags */)
  292. {
  293. ASSERT_NTC(hHeap != 0);
  294. FusionpDeleteSingletonFromPrivateHeap(hHeap, 0, p);
  295. }
  296. #endif // defined(__cplusplus)
  297. #endif