HeapAllocator.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #define HeapNew(T, ...) AllocatorNew(HeapAllocator, &HeapAllocator::Instance, T, __VA_ARGS__)
  6. #define HeapNewZ(T, ...) AllocatorNewZ(HeapAllocator, &HeapAllocator::Instance, T, __VA_ARGS__)
  7. #define HeapNewPlus(size, T, ...) AllocatorNewPlus(HeapAllocator, &HeapAllocator::Instance, size, T, __VA_ARGS__)
  8. #define HeapNewPlusZ(size, T, ...) AllocatorNewPlusZ(HeapAllocator, &HeapAllocator::Instance, size, T, __VA_ARGS__)
  9. #define HeapNewStruct(T) AllocatorNewStruct(HeapAllocator, &HeapAllocator::Instance, T);
  10. #define HeapNewStructZ(T) AllocatorNewStructZ(HeapAllocator, &HeapAllocator::Instance, T);
  11. #define HeapNewStructPlus(size, T, ...) AllocatorNewStructPlus(HeapAllocator, &HeapAllocator::Instance, size, T)
  12. #define HeapNewStructPlusZ(size, T, ...) AllocatorNewStructPlusZ(HeapAllocator, &HeapAllocator::Instance, size, T)
  13. #define HeapNewArray(T, count, ...) AllocatorNewArray(HeapAllocator, &HeapAllocator::Instance, T, count)
  14. #define HeapNewArrayZ(T, count, ...) AllocatorNewArrayZ(HeapAllocator, &HeapAllocator::Instance, T, count)
  15. #define HeapDelete(obj) AllocatorDelete(HeapAllocator, &HeapAllocator::Instance, obj)
  16. #define HeapDeletePlus(size, obj) AllocatorDeletePlus(HeapAllocator, &HeapAllocator::Instance, size, obj)
  17. #define HeapDeletePlusPrefix(size, obj) AllocatorDeletePlusPrefix(HeapAllocator, &HeapAllocator::Instance, size, obj)
  18. #define HeapDeleteArray(count, obj) AllocatorDeleteArray(HeapAllocator, &HeapAllocator::Instance, count, obj)
  19. #define HeapNewNoThrow(T, ...) AllocatorNewNoThrow(HeapAllocator, &HeapAllocator::Instance, T, __VA_ARGS__)
  20. #define HeapNewNoThrowZ(T, ...) AllocatorNewNoThrowZ(HeapAllocator, &HeapAllocator::Instance, T, __VA_ARGS__)
  21. #define HeapNewNoThrowPlus(size, T, ...) AllocatorNewNoThrowPlus(HeapAllocator, &HeapAllocator::Instance, size, T, __VA_ARGS__)
  22. #define HeapNewNoThrowPlusZ(size, T, ...) AllocatorNewNoThrowPlusZ(HeapAllocator, &HeapAllocator::Instance, size, T, __VA_ARGS__)
  23. #define HeapNewNoThrowPlusPrefixZ(size, T, ...) AllocatorNewNoThrowPlusPrefixZ(HeapAllocator, &HeapAllocator::Instance, size, T, __VA_ARGS__)
  24. #define HeapNewNoThrowStruct(T) AllocatorNewNoThrowStruct(HeapAllocator, &HeapAllocator::Instance, T)
  25. #define HeapNewNoThrowStructZ(T) AllocatorNewNoThrowStructZ(HeapAllocator, &HeapAllocator::Instance, T)
  26. #define HeapNewNoThrowArray(T, count, ...) AllocatorNewNoThrowArray(HeapAllocator, &HeapAllocator::Instance, T, count)
  27. #define HeapNewNoThrowArrayZ(T, count, ...) AllocatorNewNoThrowArrayZ(HeapAllocator, &HeapAllocator::Instance, T, count)
  28. #define NoMemProtectHeapNewNoThrow(T, ...) AllocatorNewNoThrow(HeapAllocator, HeapAllocator::GetNoMemProtectInstance(), T, __VA_ARGS__)
  29. #define NoMemProtectHeapNewNoThrowZ(T, ...) AllocatorNewNoThrowZ(HeapAllocator, HeapAllocator::GetNoMemProtectInstance(), T, __VA_ARGS__)
  30. #define NoMemProtectHeapNewNoThrowPlus(size, T, ...) AllocatorNewNoThrowPlus(HeapAllocator, HeapAllocator::GetNoMemProtectInstance(), size, T, __VA_ARGS__)
  31. #define NoMemProtectHeapNewNoThrowPlusZ(size, T, ...) AllocatorNewNoThrowPlusZ(HeapAllocator, HeapAllocator::GetNoMemProtectInstance(), size, T, __VA_ARGS__)
  32. #define NoMemProtectHeapNewNoThrowPlusPrefixZ(size, T, ...) AllocatorNewNoThrowPlusPrefixZ(HeapAllocator, HeapAllocator::GetNoMemProtectInstance(), size, T, __VA_ARGS__)
  33. #define NoMemProtectHeapNewNoThrowStruct(T) AllocatorNewNoThrowStruct(HeapAllocator, HeapAllocator::GetNoMemProtectInstance(), T)
  34. #define NoMemProtectHeapNewNoThrowStructZ(T) AllocatorNewNoThrowStructZ(HeapAllocator, HeapAllocator::GetNoMemProtectInstance(), T)
  35. #define NoMemProtectHeapNewNoThrowArray(T, count, ...) AllocatorNewNoThrowArray(HeapAllocator, HeapAllocator::GetNoMemProtectInstance(), T, count)
  36. #define NoMemProtectHeapNewNoThrowArrayZ(T, count, ...) AllocatorNewNoThrowArrayZ(HeapAllocator, HeapAllocator::GetNoMemProtectInstance(), T, count)
  37. #define NoMemProtectHeapDelete(obj) AllocatorDelete(HeapAllocator, HeapAllocator::GetNoMemProtectInstance(), obj)
  38. #define NoMemProtectHeapDeletePlus(size, obj) AllocatorDeletePlus(HeapAllocator, HeapAllocator::GetNoMemProtectInstance(), size, obj)
  39. #define NoMemProtectHeapDeletePlusPrefix(size, obj) AllocatorDeletePlusPrefix(HeapAllocator, HeapAllocator::GetNoMemProtectInstance(), size, obj)
  40. #define NoMemProtectHeapDeleteArray(count, obj) AllocatorDeleteArray(HeapAllocator, HeapAllocator::GetNoMemProtectInstance(), count, obj)
  41. #define NoCheckHeapNew(T, ...) AllocatorNew(NoCheckHeapAllocator, &NoCheckHeapAllocator::Instance, T, __VA_ARGS__)
  42. #define NoCheckHeapNewZ(T, ...) AllocatorNewZ(NoCheckHeapAllocator, &NoCheckHeapAllocator::Instance, T, __VA_ARGS__)
  43. #define NoCheckHeapNewPlus(size, T, ...) AllocatorNewPlus(NoCheckHeapAllocator, &NoCheckHeapAllocator::Instance, size, T, __VA_ARGS__)
  44. #define NoCheckHeapNewPlusZ(size, T, ...) AllocatorNewPlusZ(NoCheckHeapAllocator, &NoCheckHeapAllocator::Instance, size, T, __VA_ARGS__)
  45. #define NoCheckHeapNewStruct(T) AllocatorNewStruct(NoCheckHeapAllocator, &NoCheckHeapAllocator::Instance, T)
  46. #define NoCheckHeapNewStructZ(T) AllocatorNewStructZ(NoCheckHeapAllocator, &NoCheckHeapAllocator::Instance, T)
  47. #define NoCheckHeapNewArray(T, count, ...) AllocatorNewArray(NoCheckHeapAllocator, &NoCheckHeapAllocator::Instance, T, count)
  48. #define NoCheckHeapNewArrayZ(T, count, ...) AllocatorNewArrayZ(NoCheckHeapAllocator, &NoCheckHeapAllocator::Instance, T, count)
  49. #define NoCheckHeapDelete(obj) AllocatorDelete(NoCheckHeapAllocator, &NoCheckHeapAllocator::Instance, obj)
  50. #define NoCheckHeapDeletePlus(size, obj) AllocatorDeletePlus(NoCheckHeapAllocator, &NoCheckHeapAllocator::Instance, size, obj)
  51. #define NoCheckHeapDeleteArray(count, obj) AllocatorDeleteArray(NoCheckHeapAllocator, &NoCheckHeapAllocator::Instance, count, obj)
  52. namespace Memory
  53. {
  54. #ifdef HEAP_TRACK_ALLOC
  55. struct HeapAllocatorData;
  56. struct HeapAllocRecord
  57. {
  58. HeapAllocRecord * prev;
  59. HeapAllocRecord * next;
  60. size_t allocId;
  61. size_t size;
  62. TrackAllocData allocData;
  63. HeapAllocatorData* data;
  64. #if defined(CHECK_MEMORY_LEAK) || defined(LEAK_REPORT)
  65. StackBackTrace * stacktrace;
  66. #endif
  67. };
  68. struct HeapAllocatorData
  69. {
  70. void LogAlloc(HeapAllocRecord * record, size_t requestedBytes, TrackAllocData const& data);
  71. void LogFree(HeapAllocRecord * record);
  72. bool CheckLeaks();
  73. HeapAllocRecord * head;
  74. size_t allocCount;
  75. size_t deleteCount;
  76. size_t outstandingBytes;
  77. static uint const StackTraceDepth = 10;
  78. };
  79. #endif
  80. struct HeapAllocator
  81. {
  82. static const bool FakeZeroLengthArray = false;
  83. char * Alloc(size_t byteSize)
  84. {
  85. return AllocT<false>(byteSize);
  86. }
  87. template <bool noThrow>
  88. char * AllocT(size_t byteSize);
  89. // This exists solely to make the AllocateXXX macros more polymorphic
  90. char * AllocLeaf(size_t byteSize)
  91. {
  92. return Alloc(byteSize);
  93. }
  94. char * NoThrowAlloc(size_t byteSize)
  95. {
  96. return AllocT<true>(byteSize);
  97. }
  98. char * AllocZero(size_t byteSize)
  99. {
  100. char * buffer = Alloc(byteSize);
  101. memset(buffer, 0, byteSize);
  102. return buffer;
  103. }
  104. char * NoThrowAllocZero(size_t byteSize)
  105. {
  106. char * buffer = NoThrowAlloc(byteSize);
  107. if (buffer != nullptr)
  108. {
  109. memset(buffer, 0, byteSize);
  110. }
  111. return buffer;
  112. }
  113. void Free(void * buffer, size_t byteSize);
  114. static HeapAllocator Instance;
  115. static HeapAllocator * GetNoMemProtectInstance();
  116. #ifdef TRACK_ALLOC
  117. // Doesn't support tracking information, dummy implementation
  118. HeapAllocator * TrackAllocInfo(TrackAllocData const& data);
  119. void ClearTrackAllocInfo(TrackAllocData* data = NULL);
  120. #ifdef HEAP_TRACK_ALLOC
  121. #ifndef INTERNAL_MEM_PROTECT_HEAP_ALLOC
  122. ~HeapAllocator();
  123. #endif
  124. static void InitializeThread()
  125. {
  126. memset(&nextAllocData, 0, sizeof(nextAllocData));
  127. }
  128. static bool CheckLeaks();
  129. __declspec(thread) static TrackAllocData nextAllocData;
  130. HeapAllocatorData data;
  131. static CriticalSection cs;
  132. #endif
  133. #endif
  134. #ifdef INTERNAL_MEM_PROTECT_HEAP_ALLOC
  135. HeapAllocator(bool allowMemProtect = true);
  136. ~HeapAllocator();
  137. void FinishMemProtectHeapCollect();
  138. private:
  139. bool DoUseMemProtectHeap();
  140. static HeapAllocator NoMemProtectInstance;
  141. #if DBG
  142. bool isUsed;
  143. bool allocMemProtect;
  144. void * memProtectHeapHandle;
  145. #endif
  146. #endif
  147. }; // HeapAllocator.
  148. class NoThrowHeapAllocator
  149. {
  150. public:
  151. static const bool FakeZeroLengthArray = false;
  152. char * Alloc(size_t byteSize);
  153. char * AllocZero(size_t byteSize);
  154. void Free(void * buffer, size_t byteSize);
  155. static NoThrowHeapAllocator Instance;
  156. #ifdef TRACK_ALLOC
  157. // Doesn't support tracking information, dummy implementation
  158. NoThrowHeapAllocator * TrackAllocInfo(TrackAllocData const& data);
  159. void ClearTrackAllocInfo(TrackAllocData* data = NULL);
  160. #endif
  161. };
  162. #ifdef INTERNAL_MEM_PROTECT_HEAP_ALLOC
  163. class NoThrowNoMemProtectHeapAllocator
  164. {
  165. public:
  166. static const bool FakeZeroLengthArray = false;
  167. char * Alloc(size_t byteSize);
  168. char * AllocZero(size_t byteSize);
  169. void Free(void * buffer, size_t byteSize);
  170. static NoThrowNoMemProtectHeapAllocator Instance;
  171. #ifdef TRACK_ALLOC
  172. // Doesn't support tracking information, dummy implementation
  173. NoThrowNoMemProtectHeapAllocator * TrackAllocInfo(TrackAllocData const& data);
  174. void ClearTrackAllocInfo(TrackAllocData* data = NULL);
  175. #endif
  176. };
  177. #endif
  178. class NoCheckHeapAllocator
  179. {
  180. public:
  181. static const bool FakeZeroLengthArray = false;
  182. char * Alloc(size_t byteSize)
  183. {
  184. if (processHeap == NULL)
  185. {
  186. processHeap = GetProcessHeap();
  187. }
  188. char * buffer = (char*)HeapAlloc(processHeap, 0, byteSize);
  189. if (buffer == nullptr)
  190. {
  191. // NoCheck heap allocator is only used by debug only code, and if we fail to allocate
  192. // memory, we will just raise an exception and kill the process
  193. DebugHeap_OOM_fatal_error();
  194. }
  195. return buffer;
  196. }
  197. char * AllocZero(size_t byteSize)
  198. {
  199. if (processHeap == NULL)
  200. {
  201. processHeap = GetProcessHeap();
  202. }
  203. char * buffer = (char*)HeapAlloc(processHeap, HEAP_ZERO_MEMORY, byteSize);
  204. if (buffer == nullptr)
  205. {
  206. // NoCheck heap allocator is only used by debug only code, and if we fail to allocate
  207. // memory, we will just raise an exception and kill the process
  208. DebugHeap_OOM_fatal_error();
  209. }
  210. return buffer;
  211. }
  212. void Free(void * buffer, size_t byteSize)
  213. {
  214. Assert(processHeap != NULL);
  215. HeapFree(processHeap, 0, buffer);
  216. }
  217. #ifdef TRACK_ALLOC
  218. // Doesn't support tracking information, dummy implementation
  219. NoCheckHeapAllocator * TrackAllocInfo(TrackAllocData const& data) { return this; }
  220. void ClearTrackAllocInfo(TrackAllocData* data = NULL) {}
  221. #endif
  222. static NoCheckHeapAllocator Instance;
  223. static HANDLE processHeap;
  224. };
  225. #ifdef CHECK_MEMORY_LEAK
  226. class MemoryLeakCheck
  227. {
  228. public:
  229. MemoryLeakCheck() : head(NULL), tail(NULL), leakedBytes(0), leakedCount(0), enableOutput(true) {}
  230. ~MemoryLeakCheck();
  231. static void AddLeakDump(wchar_t const * dump, size_t bytes, size_t count);
  232. static void SetEnableOutput(bool flag) { leakCheck.enableOutput = flag; }
  233. static bool IsEnableOutput() { return leakCheck.enableOutput; }
  234. private:
  235. static MemoryLeakCheck leakCheck;
  236. struct LeakRecord
  237. {
  238. wchar_t const * dump;
  239. LeakRecord * next;
  240. };
  241. CriticalSection cs;
  242. LeakRecord * head;
  243. LeakRecord * tail;
  244. size_t leakedBytes;
  245. size_t leakedCount;
  246. bool enableOutput;
  247. };
  248. #endif
  249. } // namespace Memory
  250. #ifdef INTERNAL_MEM_PROTECT_HEAP_ALLOC
  251. //----------------------------------------
  252. // NoThrowNoMemProtectHeapAllocator overrides
  253. //----------------------------------------
  254. template <>
  255. _Ret_maybenull_ __inline void * __cdecl
  256. operator new(size_t byteSize, NoThrowNoMemProtectHeapAllocator * alloc, char * (NoThrowNoMemProtectHeapAllocator::*AllocFunc)(size_t))
  257. {
  258. return ::operator new(byteSize, alloc, true, AllocFunc);
  259. }
  260. template <>
  261. _Ret_maybenull_ __inline void * __cdecl
  262. operator new[](size_t byteSize, NoThrowNoMemProtectHeapAllocator * alloc, char * (NoThrowNoMemProtectHeapAllocator::*AllocFunc)(size_t))
  263. {
  264. return ::operator new[](byteSize, alloc, true, AllocFunc);
  265. }
  266. template <>
  267. _Ret_maybenull_ __inline void * __cdecl
  268. operator new(size_t byteSize, NoThrowNoMemProtectHeapAllocator * alloc, char * (NoThrowNoMemProtectHeapAllocator::*AllocFunc)(size_t), size_t plusSize)
  269. {
  270. return ::operator new(byteSize, alloc, true, AllocFunc, plusSize);
  271. }
  272. inline void __cdecl
  273. operator delete(void * obj, NoThrowNoMemProtectHeapAllocator * alloc, char * (NoThrowNoMemProtectHeapAllocator::*AllocFunc)(size_t))
  274. {
  275. alloc->Free(obj, (size_t)-1);
  276. }
  277. inline void __cdecl
  278. operator delete(void * obj, NoThrowNoMemProtectHeapAllocator * alloc, char * (NoThrowNoMemProtectHeapAllocator::*AllocFunc)(size_t), size_t plusSize)
  279. {
  280. alloc->Free(obj, (size_t)-1);
  281. }
  282. #else
  283. typedef NoThrowHeapAllocator NoThrowNoMemProtectHeapAllocator;
  284. #endif
  285. //----------------------------------------
  286. // Default operator new/delete overrides
  287. //----------------------------------------
  288. #if !defined(USED_IN_STATIC_LIB)
  289. _Ret_maybenull_ void * __cdecl operator new(size_t byteSize);
  290. _Ret_maybenull_ void * __cdecl operator new[](size_t byteSize);
  291. #endif
  292. //----------------------------------------
  293. // HeapAllocator overrides
  294. //----------------------------------------
  295. inline void __cdecl
  296. operator delete(void * obj, HeapAllocator * alloc, char * (HeapAllocator::*AllocFunc)(size_t))
  297. {
  298. alloc->Free(obj, (size_t)-1);
  299. }
  300. inline void __cdecl
  301. operator delete(void * obj, HeapAllocator * alloc, char * (HeapAllocator::*AllocFunc)(size_t), size_t plusSize)
  302. {
  303. alloc->Free(obj, (size_t)-1);
  304. }
  305. //----------------------------------------
  306. // NoThrowHeapAllocator overrides
  307. //----------------------------------------
  308. template <>
  309. _Ret_maybenull_ __inline void * __cdecl
  310. operator new(size_t byteSize, NoThrowHeapAllocator * alloc, char * (NoThrowHeapAllocator::*AllocFunc)(size_t))
  311. {
  312. return ::operator new(byteSize, alloc, true, AllocFunc);
  313. }
  314. template <>
  315. _Ret_maybenull_ __inline void * __cdecl
  316. operator new[](size_t byteSize, NoThrowHeapAllocator * alloc, char * (NoThrowHeapAllocator::*AllocFunc)(size_t))
  317. {
  318. return ::operator new[](byteSize, alloc, true, AllocFunc);
  319. }
  320. template <>
  321. _Ret_maybenull_ __inline void * __cdecl
  322. operator new(size_t byteSize, NoThrowHeapAllocator * alloc, char * (NoThrowHeapAllocator::*AllocFunc)(size_t), size_t plusSize)
  323. {
  324. return ::operator new(byteSize, alloc, true, AllocFunc, plusSize);
  325. }
  326. inline void __cdecl
  327. operator delete(void * obj, NoThrowHeapAllocator * alloc, char * (NoThrowHeapAllocator::*AllocFunc)(size_t))
  328. {
  329. alloc->Free(obj, (size_t)-1);
  330. }
  331. inline void __cdecl
  332. operator delete(void * obj, NoThrowHeapAllocator * alloc, char * (NoThrowHeapAllocator::*AllocFunc)(size_t), size_t plusSize)
  333. {
  334. alloc->Free(obj, (size_t)-1);
  335. }
  336. template <>
  337. _Ret_notnull_ __inline void * __cdecl
  338. operator new(size_t byteSize, NoCheckHeapAllocator * alloc, char * (NoCheckHeapAllocator::*AllocFunc)(size_t))
  339. {
  340. Assert(byteSize != 0);
  341. void * buffer = (alloc->*AllocFunc)(byteSize);
  342. return buffer;
  343. }
  344. template <>
  345. _Ret_notnull_ __inline void * __cdecl
  346. operator new(size_t byteSize, NoCheckHeapAllocator * alloc, char * (NoCheckHeapAllocator::*AllocFunc)(size_t), size_t plusSize)
  347. {
  348. Assert(byteSize != 0);
  349. Assert(plusSize != 0);
  350. void * buffer = (alloc->*AllocFunc)(AllocSizeMath::Add(byteSize, plusSize));
  351. return buffer;
  352. }
  353. _Ret_notnull_ __inline void * __cdecl
  354. operator new[](size_t byteSize, NoCheckHeapAllocator * alloc, char * (NoCheckHeapAllocator::*AllocFunc)(size_t))
  355. {
  356. void * buffer = (alloc->*AllocFunc)(byteSize);
  357. return buffer;
  358. }
  359. inline void __cdecl
  360. operator delete(void * obj, NoCheckHeapAllocator * alloc, char * (NoCheckHeapAllocator::*AllocFunc)(size_t))
  361. {
  362. alloc->Free(obj, (size_t)-1);
  363. }
  364. inline void __cdecl
  365. operator delete(void * obj, NoCheckHeapAllocator * alloc, char * (NoCheckHeapAllocator::*AllocFunc)(size_t), size_t plusSize)
  366. {
  367. alloc->Free(obj, (size_t)-1);
  368. }