Leaked source code of windows server 2003
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.

933 lines
27 KiB

  1. #include "stdinc.h"
  2. #include "fusionheap.h"
  3. #include "fusionbuffer.h"
  4. #include "debmacro.h"
  5. #include "numberof.h"
  6. #define MAX_VTBL_ENTRIES 256
  7. FUSION_HEAP_HANDLE g_hHeap = NULL;
  8. #if FUSION_DEBUG_HEAP
  9. FUSION_HEAP_HANDLE g_hDebugInfoHeap = NULL;
  10. LONG g_FusionHeapAllocationCount = 0;
  11. LONG g_FusionHeapAllocationToBreakOn = 0;
  12. PVOID g_FusionHeapDeallocationPtrToBreakOn = NULL;
  13. PVOID g_FusionHeapAllocationPtrToBreakOn = NULL;
  14. WCHAR g_FusionModuleNameUnknown[] = L"(Unknown module)";
  15. // NTRAID#NTBUG9 - 589824 - 2002/03/26 - xiaoyuw:
  16. // This is used to support uitl.lib on win98 because HeapXXX is not avaiable on win98.
  17. // FusionpHeapLock is defined to replace HeapLock to work around for certain codepath,
  18. // and there would be some problem if debug heap is enabled, for example, HeapWalk is
  19. // always upsupported at win9x.
  20. //
  21. // we could consider to remove this someday. and just set FUSION_DEBUG_HEAP to be 0 if
  22. // the system is a win9x. FUSION_DISABLE_DEBUG_HEAP_ON_WIN98 is has already been provided.
  23. #if defined(FUSION_WIN2000)
  24. CRITICAL_SECTION g_FusionpWin9xHeapLock;
  25. #endif
  26. //
  27. // g_FusionHeapOperationCount is used to keep track of the total number of
  28. // allocations and deallocations; the heap is verified each
  29. // g_FusionHeapCheckFrequency operations. Set it to zero to disable any
  30. // non-explicit checks.
  31. //
  32. LONG g_FusionHeapOperationCount = 0;
  33. LONG g_FusionHeapCheckFrequency = 1;
  34. // Set g_FusionUsePrivateHeap to TRUE in your DllMain prior to
  35. // calling FusionpInitializeHeap() to get a private heap for this DLL.
  36. BOOL g_FusionUsePrivateHeap = FALSE;
  37. //
  38. // Setting this boolean enables stack-back-tracing for allocations. This
  39. // will make your life infinitely easier when trying to debug leaks. However,
  40. // it will eat piles more debug heap. Set it via a breakin or in your DllMain.
  41. //
  42. // ABSOLUTELY DO NOT CHECK THIS IN WITH STACK TRACKING ENABLED!!!!!
  43. //
  44. BOOL g_FusionHeapTrackStackTraces = FALSE;
  45. // g_FusionHeapPostAllocationBytes is the number of extra bytes
  46. // to allocate and write a pattern on to watch for people overwriting
  47. // their allocations.
  48. LONG g_FusionHeapPostAllocationBytes = 8;
  49. UCHAR g_FusionHeapPostAllocationChar = 0xf0;
  50. UCHAR g_FusionHeapAllocationPoisonChar = 0xfa;
  51. UCHAR g_FusionHeapDeallocationPoisonChar = 0xfd;
  52. // HINSTANCE used when initializing the heap; we use it later to report the
  53. // dll name.
  54. HINSTANCE g_FusionHeapHInstance;
  55. #endif // FUSION_DEBUG_HEAP
  56. BOOL
  57. FusionpInitializeHeap(
  58. HINSTANCE hInstance
  59. )
  60. {
  61. #if FUSION_DEBUG_HEAP
  62. BOOL fSuccess = FALSE;
  63. #if defined(FUSION_WIN2000)
  64. if (!FusionpInitializeCriticalSection(&g_FusionpWin9xHeapLock))
  65. {
  66. goto Exit;
  67. }
  68. #endif
  69. #if FUSION_PRIVATE_HEAP
  70. g_hHeap = (FUSION_HEAP_HANDLE) ::HeapCreate(0, 0, 0);
  71. if (g_hHeap == NULL)
  72. {
  73. ::FusionpDbgPrintEx(
  74. FUSION_DBG_LEVEL_ERROR,
  75. "SXS: Failed to create private heap. FusionpGetLastWin32Error() = %d\n", ::FusionpGetLastWin32Error());
  76. goto Exit;
  77. }
  78. #else
  79. if (g_FusionUsePrivateHeap)
  80. {
  81. g_hHeap = (FUSION_HEAP_HANDLE) ::HeapCreate(0, 0, 0);
  82. if (g_hHeap == NULL)
  83. {
  84. ::FusionpDbgPrintEx(
  85. FUSION_DBG_LEVEL_ERROR,
  86. "SXS: Failed to create private heap. FusionpGetLastWin32Error() = %d\n", ::FusionpGetLastWin32Error());
  87. goto Exit;
  88. }
  89. }
  90. else
  91. {
  92. g_hHeap = (FUSION_HEAP_HANDLE) ::GetProcessHeap();
  93. if (g_hHeap == NULL)
  94. {
  95. ::FusionpDbgPrintEx(
  96. FUSION_DBG_LEVEL_ERROR,
  97. "SXS: Failed to get process default heap. FusionpGetLastWin32Error() = %d\n", ::FusionpGetLastWin32Error());
  98. goto Exit;
  99. }
  100. }
  101. #endif
  102. g_hDebugInfoHeap = (FUSION_HEAP_HANDLE) ::HeapCreate(0, 0, 0);
  103. if (g_hDebugInfoHeap == NULL)
  104. {
  105. goto Exit;
  106. }
  107. g_FusionHeapHInstance = hInstance;
  108. fSuccess = TRUE;
  109. Exit:
  110. return fSuccess;
  111. #else
  112. g_hHeap = (FUSION_HEAP_HANDLE) ::GetProcessHeap();
  113. return TRUE;
  114. #endif
  115. }
  116. VOID
  117. FusionpUninitializeHeap()
  118. {
  119. #if FUSION_DEBUG_HEAP
  120. BOOL fHeapLocked = FALSE;
  121. BOOL fDebugHeapLocked = FALSE;
  122. PROCESS_HEAP_ENTRY phe;
  123. WCHAR DllName[MAX_PATH / sizeof(WCHAR)]; // keep stack frame to ~MAX_PATH bytes
  124. if (g_hHeap == NULL || g_hDebugInfoHeap == NULL)
  125. goto Exit;
  126. DllName[0] = 0;
  127. if (g_FusionHeapHInstance != NULL)
  128. {
  129. DWORD dwLen;
  130. dwLen = ::GetModuleFileNameW(g_FusionHeapHInstance, DllName, NUMBER_OF(DllName));
  131. if (dwLen >= NUMBER_OF(DllName))
  132. dwLen = NUMBER_OF(DllName) - 1;
  133. DllName[dwLen] = UNICODE_NULL;
  134. }
  135. if (!::HeapLock(g_hHeap))
  136. goto ReportError;
  137. fHeapLocked = TRUE;
  138. if (!::HeapLock(g_hDebugInfoHeap))
  139. goto ReportError;
  140. fDebugHeapLocked = TRUE;
  141. // Walk the debug heap looking for allocations...
  142. phe.lpData = NULL;
  143. while (::HeapWalk(g_hDebugInfoHeap, &phe))
  144. {
  145. if (!(phe.wFlags & PROCESS_HEAP_ENTRY_BUSY))
  146. continue;
  147. PFUSION_HEAP_ALLOCATION_TRACKER pTracker = (PFUSION_HEAP_ALLOCATION_TRACKER) phe.lpData;
  148. if (pTracker == NULL)
  149. continue;
  150. if (pTracker->Prefix == NULL)
  151. continue;
  152. // Stop the prefix from pointing at the debug info; we're doing to destroy the debug heap.
  153. pTracker->Prefix->Tracker = NULL;
  154. }
  155. //
  156. // On invalid function, meaning HeapWalk is not defined, just exit.
  157. // Same for no-more-items, meaning the end of the list is nigh. We
  158. // make the assumption that none of the other functions in the loop
  159. // can fail with E_N_M_I or E_I_F - this may be a fallacy for later.
  160. //
  161. switch (::FusionpGetLastWin32Error())
  162. {
  163. case ERROR_INVALID_FUNCTION:
  164. case ERROR_NO_MORE_ITEMS:
  165. goto Exit;
  166. default:
  167. goto ReportError;
  168. }
  169. // Original code:
  170. //
  171. // if (::FusionpGetLastWin32Error() != ERROR_NO_MORE_ITEMS)
  172. // goto ReportError;
  173. //
  174. goto Exit;
  175. ReportError:
  176. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "%s: FusionpUninitializeHeap() encountered an error; FusionpGetLastWin32Error() = %d\n", DllName, ::FusionpGetLastWin32Error());
  177. Exit:
  178. if (fDebugHeapLocked)
  179. ::HeapUnlock(g_hDebugInfoHeap);
  180. if (fHeapLocked)
  181. ::HeapUnlock(g_hHeap);
  182. if (g_hDebugInfoHeap != NULL)
  183. ::HeapDestroy(g_hDebugInfoHeap);
  184. g_hHeap = NULL;
  185. g_hDebugInfoHeap = NULL;
  186. #if defined(FUSION_WIN2000)
  187. DeleteCriticalSection(&g_FusionpWin9xHeapLock);
  188. #endif
  189. #endif
  190. }
  191. #if FUSION_DEBUG_HEAP
  192. VOID
  193. FusionpDumpHeap(
  194. PCWSTR PerLinePrefixWithoutSpaces
  195. )
  196. {
  197. BOOL fHeapLocked = FALSE;
  198. BOOL fDebugHeapLocked = FALSE;
  199. PROCESS_HEAP_ENTRY phe;
  200. WCHAR DllName[MAX_PATH / sizeof(WCHAR) / 2];
  201. WCHAR PerLinePrefix[MAX_PATH / sizeof(WCHAR) / 2]; // only MAX_PATH bytes for prev two variables
  202. const static WCHAR PerLineSpacesPrefix[] = L" ";
  203. DWORD dwLen;
  204. if (g_hHeap == NULL || g_hDebugInfoHeap == NULL)
  205. goto Exit;
  206. // sprintf is overkill, but convenient, and it lets us reuse the buffer size support..
  207. ::_snwprintf(PerLinePrefix, NUMBER_OF(PerLinePrefix), L"%s%s", PerLinePrefixWithoutSpaces, PerLineSpacesPrefix);
  208. PerLinePrefix[NUMBER_OF(PerLinePrefix) - 1] = L'\0';
  209. DllName[0] = 0;
  210. dwLen = ::GetModuleFileNameW(g_FusionHeapHInstance, DllName, NUMBER_OF(DllName));
  211. if (dwLen >= NUMBER_OF(DllName))
  212. dwLen = NUMBER_OF(DllName) - 1;
  213. DllName[dwLen] = UNICODE_NULL;
  214. try
  215. {
  216. if (!::HeapLock(g_hHeap))
  217. goto ReportError;
  218. fHeapLocked = TRUE;
  219. if (!::HeapLock(g_hDebugInfoHeap))
  220. goto ReportError;
  221. fDebugHeapLocked = TRUE;
  222. // Walk the debug heap looking for allocations...
  223. phe.lpData = NULL;
  224. while (::HeapWalk(g_hDebugInfoHeap, &phe))
  225. {
  226. PCSTR HeapString;
  227. SIZE_T cbToShow;
  228. if (!(phe.wFlags & PROCESS_HEAP_ENTRY_BUSY))
  229. continue;
  230. PFUSION_HEAP_ALLOCATION_TRACKER pTracker = (PFUSION_HEAP_ALLOCATION_TRACKER) phe.lpData;
  231. if (pTracker == NULL)
  232. continue;
  233. if (pTracker->Prefix == NULL)
  234. continue;
  235. // If the caller wanted us to not report this allocation as being leaky, don't.
  236. if (pTracker->Flags & FUSION_HEAP_DO_NOT_REPORT_LEAKED_ALLOCATION)
  237. continue;
  238. if (pTracker->Heap == g_hHeap)
  239. HeapString = "default heap";
  240. else
  241. HeapString = "custom heap";
  242. cbToShow = pTracker->RequestedSize;
  243. if (cbToShow > 64)
  244. cbToShow = 64;
  245. ::FusionpDbgPrintEx(
  246. FUSION_DBG_LEVEL_ERROR,
  247. "%s(%u): Memory allocation leaked!\n", pTracker->FileName, pTracker->Line);
  248. ::FusionpDbgPrintEx(
  249. FUSION_DBG_LEVEL_ERROR,
  250. "%SLeaked %S allocation #%u (0x%lx) at %p \"%s\" (tracked by %p; allocated from heap %p - %s)\n"
  251. "%S Requested bytes/Allocated bytes: %Iu / %Iu (dumping %Iu bytes)\n",
  252. PerLinePrefix, DllName, pTracker->SequenceNumber, pTracker->SequenceNumber, pTracker->Prefix, pTracker->Expression, pTracker, pTracker->Heap, HeapString,
  253. PerLinePrefix, pTracker->RequestedSize, pTracker->AllocationSize, cbToShow);
  254. ::FusionpDbgPrintEx(
  255. FUSION_DBG_LEVEL_ERROR,
  256. "%s Allocated at line %u of %s\n",
  257. PerLinePrefix, pTracker->Line, pTracker->FileName);
  258. #if FUSION_ENABLE_FROZEN_STACK
  259. if (pTracker->pvFrozenStack)
  260. ::FusionpOutputFrozenStack(
  261. FUSION_DBG_LEVEL_ERROR,
  262. "SXS",
  263. (PFROZEN_STACK)pTracker->pvFrozenStack);
  264. #endif
  265. ::FusionpDbgPrintBlob(
  266. FUSION_DBG_LEVEL_ERROR,
  267. pTracker->Prefix + 1,
  268. cbToShow,
  269. PerLinePrefix);
  270. }
  271. //
  272. // On invalid function, meaning HeapWalk is not defined, just exit.
  273. // Same for no-more-items, meaning the end of the list is nigh. We
  274. // make the assumption that none of the other functions in the loop
  275. // can fail with E_N_M_I or E_I_F - this may be a fallacy for later.
  276. //
  277. switch (::FusionpGetLastWin32Error())
  278. {
  279. case ERROR_INVALID_FUNCTION:
  280. case ERROR_NO_MORE_ITEMS:
  281. goto Exit;
  282. default:
  283. goto ReportError;
  284. }
  285. // Original code:
  286. //
  287. // if (::FusionpGetLastWin32Error() != ERROR_NO_MORE_ITEMS)
  288. // goto ReportError;
  289. //
  290. }
  291. catch(...)
  292. {
  293. }
  294. goto Exit;
  295. ReportError:
  296. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "%S: FusionpDumpHeap() encountered an error; FusionpGetLastWin32Error() = %d\n", DllName, ::FusionpGetLastWin32Error());
  297. Exit:
  298. if (fDebugHeapLocked)
  299. ::HeapUnlock(g_hDebugInfoHeap);
  300. if (fHeapLocked)
  301. ::HeapUnlock(g_hHeap);
  302. }
  303. VOID
  304. FusionpValidateHeap(
  305. FUSION_HEAP_HANDLE hFusionHeap
  306. )
  307. {
  308. FN_TRACE();
  309. BOOL fHeapLocked = FALSE;
  310. BOOL fDebugHeapLocked = FALSE;
  311. PROCESS_HEAP_ENTRY phe;
  312. SIZE_T i;
  313. WCHAR DllName[MAX_PATH / sizeof(WCHAR)]; // keep stack frame to ~MAX_PATH bytes
  314. PCWSTR DllNamePointer = DllName;
  315. DWORD dwCallStatus;
  316. HANDLE hHeap = (HANDLE) hFusionHeap;
  317. DllName[0] = 0;
  318. if (g_hDebugInfoHeap == NULL)
  319. goto Exit;
  320. //
  321. // Get the current module's name, but don't print garbage if it fails.
  322. //
  323. dwCallStatus = ::GetModuleFileNameW(g_FusionHeapHInstance, DllName, NUMBER_OF(DllName));
  324. if (!dwCallStatus)
  325. {
  326. #if defined(FUSION_WIN2000)
  327. if ((GetVersion() & 0x80000000) != 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
  328. {
  329. DllNamePointer = L"Win9x..";
  330. }
  331. else
  332. #endif
  333. {
  334. ::FusionpDbgPrintEx(
  335. FUSION_DBG_LEVEL_ERROR,
  336. "FusionpValidateHeap() was unable to get the current module name, code = %d\n",
  337. ::FusionpGetLastWin32Error());
  338. //
  339. // Blank the name, insert something relevant.
  340. //
  341. DllNamePointer = g_FusionModuleNameUnknown;
  342. }
  343. }
  344. try
  345. {
  346. if (hHeap != NULL)
  347. {
  348. if (!::HeapLock(hHeap))
  349. goto ReportError;
  350. fHeapLocked = TRUE;
  351. }
  352. if (!::HeapLock(g_hDebugInfoHeap))
  353. goto ReportError;
  354. fDebugHeapLocked = TRUE;
  355. // Walk the debug heap looking for allocations...
  356. phe.lpData = NULL;
  357. while (::HeapWalk(g_hDebugInfoHeap, &phe))
  358. {
  359. PCSTR HeapString;
  360. SIZE_T cbToShow;
  361. if (!(phe.wFlags & PROCESS_HEAP_ENTRY_BUSY))
  362. continue;
  363. PFUSION_HEAP_ALLOCATION_TRACKER pTracker = (PFUSION_HEAP_ALLOCATION_TRACKER) phe.lpData;
  364. if (pTracker == NULL)
  365. continue;
  366. if (pTracker->Prefix == NULL)
  367. continue;
  368. // If we're checking only a particular heap, skip...
  369. if ((hHeap != NULL) && (pTracker->Heap != hHeap))
  370. continue;
  371. if (pTracker->PostAllocPoisonArea == NULL)
  372. continue;
  373. // The area should have been NULL if the count of bytes was nonzero...
  374. ASSERT(pTracker->PostAllocPoisonBytes != 0);
  375. PUCHAR PostAllocPoisonArea = pTracker->PostAllocPoisonArea;
  376. const UCHAR PostAllocPoisonChar = pTracker->PostAllocPoisonChar;
  377. const ULONG PostAllocPoisonBytes = pTracker->PostAllocPoisonBytes;
  378. for (i=0; i<PostAllocPoisonBytes; i++)
  379. {
  380. if (PostAllocPoisonArea[i] != PostAllocPoisonChar)
  381. break;
  382. }
  383. // The poison area looks good; skip...
  384. if (i == PostAllocPoisonBytes)
  385. continue;
  386. if (pTracker->Heap == g_hHeap)
  387. HeapString = "default heap";
  388. else
  389. HeapString = "custom heap";
  390. cbToShow = pTracker->RequestedSize;
  391. if (cbToShow > 64)
  392. cbToShow = 64;
  393. ::FusionpDbgPrintEx(
  394. FUSION_DBG_LEVEL_ERROR,
  395. "Wrote past end of %S allocation #%u (0x%lx) at %p \"%s\" (tracked by %p; allocated from heap %p - %s)\n"
  396. " Requested bytes/Allocated bytes: %Iu / %Iu (dumping %Iu bytes)\n",
  397. DllNamePointer, pTracker->SequenceNumber, pTracker->SequenceNumber, pTracker->Prefix, pTracker->Expression, pTracker, pTracker->Heap, HeapString,
  398. pTracker->RequestedSize, pTracker->AllocationSize, cbToShow);
  399. ::FusionpDbgPrintEx(
  400. FUSION_DBG_LEVEL_ERROR,
  401. " Allocated at line %u of %s\n",
  402. pTracker->Line, pTracker->FileName);
  403. ::FusionpDbgPrintBlob(
  404. FUSION_DBG_LEVEL_ERROR,
  405. pTracker->Prefix + 1,
  406. cbToShow,
  407. L"");
  408. ::FusionpDbgPrintBlob(
  409. FUSION_DBG_LEVEL_ERROR,
  410. pTracker->PostAllocPoisonArea,
  411. pTracker->PostAllocPoisonBytes,
  412. L"");
  413. }
  414. //
  415. // On invalid function, meaning HeapWalk is not defined, just exit.
  416. // Same for no-more-items, meaning the end of the list is nigh. We
  417. // make the assumption that none of the other functions in the loop
  418. // can fail with E_N_M_I or E_I_F - this may be a fallacy for later.
  419. //
  420. switch (::FusionpGetLastWin32Error())
  421. {
  422. case ERROR_INVALID_FUNCTION:
  423. case ERROR_NO_MORE_ITEMS:
  424. goto Exit;
  425. default:
  426. goto ReportError;
  427. }
  428. // Original code:
  429. //
  430. // if (::FusionpGetLastWin32Error() != ERROR_NO_MORE_ITEMS)
  431. // goto ReportError;
  432. //
  433. }
  434. catch(...)
  435. {
  436. FusionpDbgPrintEx(
  437. FUSION_DBG_LEVEL_ERROR,
  438. "%S: Exception while validating heap.\n", DllNamePointer);
  439. }
  440. goto Exit;
  441. ReportError:
  442. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "%S: FusionpValidateHeap() encountered an error; FusionpGetLastWin32Error() = %d\n", DllNamePointer, ::FusionpGetLastWin32Error());
  443. Exit:
  444. if (fDebugHeapLocked)
  445. ::HeapUnlock(g_hDebugInfoHeap);
  446. if (fHeapLocked)
  447. ::HeapUnlock(hHeap);
  448. }
  449. #if defined(FUSION_WIN)
  450. #define FusionpHeapLock HeapLock
  451. #define FusionpHeapUnlock HeapUnlock
  452. #elif defined(FUSION_WIN2000)
  453. BOOL
  454. FusionpHeapLock(
  455. HANDLE hHeap
  456. )
  457. {
  458. if ((GetVersion() & 0x80000000) == 0)
  459. { // NT
  460. return HeapLock(hHeap);
  461. }
  462. else
  463. { // Win9x
  464. EnterCriticalSection(&g_FusionpWin9xHeapLock);
  465. return TRUE;
  466. }
  467. }
  468. BOOL
  469. FusionpHeapUnlock(
  470. HANDLE hHeap
  471. )
  472. {
  473. if ((GetVersion() & 0x80000000) == 0)
  474. { // NT
  475. return HeapUnlock(hHeap);
  476. }
  477. else
  478. { // Win9x
  479. LeaveCriticalSection(&g_FusionpWin9xHeapLock);
  480. return TRUE;
  481. }
  482. }
  483. #else
  484. #error
  485. #endif
  486. PVOID
  487. FusionpDbgHeapAlloc(
  488. FUSION_HEAP_HANDLE hHeap,
  489. DWORD dwHeapAllocFlags,
  490. SIZE_T cb,
  491. PCSTR pszFile,
  492. INT nLine,
  493. PCSTR pszExpression,
  494. DWORD dwFusionFlags
  495. )
  496. {
  497. FN_TRACE();
  498. BOOL fSuccess = FALSE;
  499. BOOL fDebugHeapLocked = FALSE;
  500. SIZE_T cbAdditionalBytes = 0;
  501. #if FUSION_ENABLE_FROZEN_STACK
  502. // BOOL bShouldTraceStack = (g_FusionHeapTrackStackTraces && (::TlsGetValue(g_FusionHeapTrackingDisabledDepthTLSIndex) == 0));
  503. BOOL bShouldTraceStack = g_FusionHeapTrackStackTraces;
  504. FROZEN_STACK Prober = { 0 };
  505. #endif
  506. ASSERT(hHeap != NULL);
  507. LONG lAllocationSequenceNumber = ::InterlockedIncrement(&g_FusionHeapAllocationCount);
  508. if ((g_FusionHeapAllocationToBreakOn != 0) &&
  509. (lAllocationSequenceNumber == g_FusionHeapAllocationToBreakOn))
  510. {
  511. // Break in to the debugger, even if we're not in a checked build.
  512. FUSION_DEBUG_BREAK_IN_FREE_BUILD();
  513. }
  514. LONG lOperationSequenceNumber = ::InterlockedIncrement(&g_FusionHeapOperationCount);
  515. if ((g_FusionHeapCheckFrequency != 0) && ((lOperationSequenceNumber % g_FusionHeapCheckFrequency) == 0))
  516. {
  517. // Check the active heap allocations for correct post-block signatures...
  518. // NTRAID#NTBUG9 - 589824 - 2002/03/26 - xiaoyuw:
  519. // this call is very reasonable except costly, why we disable it?
  520. // ::FusionpValidateHeap(NULL);
  521. }
  522. PSTR psz = NULL;
  523. SIZE_T cbFile = (pszFile == NULL) ? 0 : ::strlen(pszFile) + 1;
  524. SIZE_T cbExpression = (pszExpression == NULL) ? 0 : ::strlen(pszExpression) + 1;
  525. PFUSION_HEAP_ALLOCATION_TRACKER pTracker = NULL;
  526. // Make a copy of the global variable so that if someone breaks in in the debugger
  527. // and changes it while we're in the middle of this code we don't die horribly.
  528. const ULONG cbPostAllocationBytes = g_FusionHeapPostAllocationBytes;
  529. const UCHAR chPostAllocationChar = g_FusionHeapPostAllocationChar;
  530. const SIZE_T cbToAllocate = (sizeof(FUSION_HEAP_PREFIX) + cb + cbPostAllocationBytes);
  531. const PFUSION_HEAP_PREFIX pPrefix = reinterpret_cast<PFUSION_HEAP_PREFIX>(::HeapAlloc(hHeap, dwHeapAllocFlags, cbToAllocate));
  532. if (pPrefix == NULL)
  533. {
  534. ::FusionpDbgPrintEx(
  535. FUSION_DBG_LEVEL_ERROR,
  536. "%s(%d): [SXS.DLL] Heap allocation failure allocating %Iu (really %Iu) bytes\n", pszFile, nLine, cb, cbToAllocate);
  537. ::SetLastError(FUSION_WIN32_ALLOCFAILED_ERROR);
  538. return NULL;
  539. }
  540. // lock the debug info heap to allocate memory for pTracker
  541. if (!::FusionpHeapLock(g_hDebugInfoHeap))
  542. goto Exit;
  543. fDebugHeapLocked = TRUE;
  544. //
  545. // Are we tracing the stack? If so, then we need to allocate some extra bytes
  546. // on the end of this tracker to store the context.
  547. //
  548. #if FIXBEFORECHECKIN
  549. if (bShouldTraceStack)
  550. {
  551. BOOL bSuccess = ::FusionpFreezeStack(NULL, 0, &Prober);
  552. if (!bSuccess && (::FusionpGetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)) {
  553. cbAdditionalBytes = sizeof(FROZEN_STACK) + (sizeof(TRACECONTEXT) * Prober.ulMaxDepth);
  554. } else {
  555. cbAdditionalBytes = 0;
  556. bShouldTraceStack = FALSE;
  557. }
  558. }
  559. else
  560. #endif // FIXBEFORECHECKIN
  561. cbAdditionalBytes = 0;
  562. pTracker = reinterpret_cast<PFUSION_HEAP_ALLOCATION_TRACKER>(::HeapAlloc(
  563. g_hDebugInfoHeap,
  564. 0,
  565. sizeof(FUSION_HEAP_ALLOCATION_TRACKER)
  566. + FUSION_HEAP_ROUND_SIZE(cbFile)
  567. + FUSION_HEAP_ROUND_SIZE(cbExpression)
  568. + FUSION_HEAP_ROUND_SIZE(cbAdditionalBytes)));
  569. if (pTracker == NULL)
  570. {
  571. ::FusionpDbgPrintEx(
  572. FUSION_DBG_LEVEL_ERROR,
  573. "%s(%d): [SXS.DLL] Heap allocation failure allocating tracker for %lu bytes\n", pszFile, nLine, cb);
  574. ::HeapFree(hHeap, 0, pPrefix);
  575. ::SetLastError(FUSION_WIN32_ALLOCFAILED_ERROR);
  576. goto Exit;
  577. }
  578. pPrefix->Tracker = pTracker;
  579. pTracker->Prefix = pPrefix;
  580. pTracker->Heap = hHeap;
  581. pTracker->SequenceNumber = lAllocationSequenceNumber;
  582. pTracker->PostAllocPoisonBytes = cbPostAllocationBytes;
  583. if (cbPostAllocationBytes != 0)
  584. {
  585. const PUCHAR pb = (UCHAR *) (((ULONG_PTR) (pPrefix + 1)) + cb);
  586. ULONG i;
  587. pTracker->PostAllocPoisonArea = (PUCHAR) pb;
  588. pTracker->PostAllocPoisonChar = chPostAllocationChar;
  589. for (i=0; i<cbPostAllocationBytes; i++)
  590. pb[i] = chPostAllocationChar;
  591. }
  592. else
  593. {
  594. pTracker->PostAllocPoisonArea = NULL;
  595. }
  596. psz = (PSTR) (pTracker + 1);
  597. if (cbFile != 0)
  598. {
  599. pTracker->FileName = psz;
  600. memcpy(psz, pszFile, cbFile);
  601. psz += FUSION_HEAP_ROUND_SIZE(cbFile);
  602. }
  603. else
  604. pTracker->FileName = NULL;
  605. if (cbExpression != 0)
  606. {
  607. pTracker->Expression = psz;
  608. memcpy(psz, pszExpression, cbExpression);
  609. psz += FUSION_HEAP_ROUND_SIZE(cbExpression);
  610. }
  611. else
  612. pTracker->Expression = NULL;
  613. #if FUSION_ENABLE_FROZEN_STACK
  614. //
  615. // Set up our stack tracker
  616. //
  617. if (bShouldTraceStack)
  618. {
  619. PFROZEN_STACK pStack = (PFROZEN_STACK)psz;
  620. pTracker->pvFrozenStack = pStack;
  621. pStack->ulDepth = 0;
  622. pStack->ulMaxDepth = Prober.ulMaxDepth;
  623. if (!::FusionpFreezeStack(0, pStack))
  624. pTracker->pvFrozenStack = NULL;
  625. }
  626. //
  627. // Otherwise, no stack for you.
  628. //
  629. else
  630. {
  631. pTracker->pvFrozenStack = NULL;
  632. }
  633. #endif
  634. pTracker->Line = nLine;
  635. pTracker->Flags = dwFusionFlags;
  636. pTracker->RequestedSize = cb;
  637. pTracker->AllocationSize = cb + sizeof(FUSION_HEAP_PREFIX);
  638. // poison the allocation...
  639. memset((pPrefix + 1), g_FusionHeapAllocationPoisonChar, cb);
  640. // NTRAID#NTBUG9 - 589824 - 2002/03/26 - xiaoyuw:
  641. // shouldn't pPrefix be reset after memset is called?
  642. if ((g_FusionHeapAllocationPtrToBreakOn != 0) &&
  643. ((pPrefix + 1) == g_FusionHeapAllocationPtrToBreakOn))
  644. {
  645. // Break in to the debugger, even if we're not in a checked build.
  646. FUSION_DEBUG_BREAK_IN_FREE_BUILD();
  647. }
  648. fSuccess = TRUE;
  649. Exit:
  650. if (fDebugHeapLocked){
  651. // NTRAID#NTBUG9 - 589824 - 2002/03/26 - xiaoyuw:
  652. // (1) use CSxsPreserveLastError instead,
  653. // (2) in the case of failure call of FusionpHeapUnlock, we stil want to keep the error if fSuccess == TRUE at this moment.
  654. DWORD dwLastError = ::FusionpGetLastWin32Error();
  655. ::FusionpHeapUnlock(g_hDebugInfoHeap);
  656. ::SetLastError(dwLastError);
  657. }
  658. if (fSuccess)
  659. return (PVOID) (pPrefix + 1);
  660. else
  661. return NULL;
  662. }
  663. BOOL
  664. FusionpDbgHeapFree(
  665. FUSION_HEAP_HANDLE hHeap,
  666. DWORD dwHeapFreeFlags,
  667. PVOID pv
  668. )
  669. {
  670. FN_TRACE();
  671. PFUSION_HEAP_ALLOCATION_TRACKER pTracker;
  672. BOOL fResult = FALSE;
  673. ASSERT(hHeap != NULL);
  674. if (pv == NULL)
  675. return FALSE;
  676. if ((g_FusionHeapDeallocationPtrToBreakOn != NULL) &&
  677. (pv == g_FusionHeapDeallocationPtrToBreakOn))
  678. {
  679. // Break in to the debugger, even if we're not in a checked build.
  680. FUSION_DEBUG_BREAK_IN_FREE_BUILD();
  681. }
  682. // Let's see if its one of our funky ones...
  683. PFUSION_HEAP_PREFIX p = (PFUSION_HEAP_PREFIX) (((ULONG_PTR) pv) - sizeof(FUSION_HEAP_PREFIX));
  684. if (!::HeapValidate(hHeap, 0, p)) {
  685. // HeapValidate failed. Fatal. Just leak the memory for now...
  686. // ASSERT(0);
  687. return FALSE;
  688. }
  689. if (!::HeapValidate(g_hDebugInfoHeap, 0, p->Tracker)) {
  690. // HeapValidate failed. Fatal. Just leak the memory for now...
  691. // ASSERT(0);
  692. return FALSE;
  693. }
  694. pTracker = p->Tracker;
  695. ASSERT(pTracker->Heap == hHeap);
  696. p->Tracker->Prefix = NULL;
  697. // poison the deallocation...
  698. memset(p, g_FusionHeapDeallocationPoisonChar, pTracker->AllocationSize);
  699. ::HeapFree(g_hDebugInfoHeap, 0, pTracker);
  700. fResult = ::HeapFree(hHeap, dwHeapFreeFlags, p);
  701. return fResult;
  702. }
  703. VOID
  704. FusionpDeallocateTracker(
  705. PFUSION_HEAP_PREFIX p
  706. )
  707. {
  708. CSxsPreserveLastError ple;
  709. PFUSION_HEAP_ALLOCATION_TRACKER pTracker = p->Tracker;
  710. ::HeapFree(g_hDebugInfoHeap, 0, pTracker);
  711. p->Tracker = NULL;
  712. ple.Restore();
  713. }
  714. VOID *
  715. FusionpGetFakeVTbl()
  716. {
  717. VOID *pvHeap;
  718. // Always allocate the fake vtbl from the process heap so that it survives us nomatter what.
  719. pvHeap = HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_VTBL_ENTRIES * sizeof(void *));
  720. return pvHeap;
  721. }
  722. VOID
  723. FusionpDontTrackBlk(
  724. VOID *pv
  725. )
  726. {
  727. PFUSION_HEAP_PREFIX p;
  728. p = (PFUSION_HEAP_PREFIX) (((ULONG_PTR)pv) - sizeof(FUSION_HEAP_PREFIX));
  729. ::FusionpDeallocateTracker(p);
  730. p->Tracker = NULL;
  731. }
  732. #else // FUSION_DEBUG_HEAP
  733. LPVOID
  734. WINAPI
  735. FusionpHeapAlloc(
  736. IN HANDLE hHeap,
  737. IN DWORD dwFlags,
  738. IN SIZE_T dwBytes
  739. )
  740. {
  741. LPVOID p = ::HeapAlloc(hHeap, dwFlags, dwBytes);
  742. if (p == NULL)
  743. {
  744. ::SetLastError(FUSION_WIN32_ALLOCFAILED_ERROR);
  745. }
  746. return p;
  747. }
  748. LPVOID
  749. WINAPI
  750. FusionpHeapReAlloc(
  751. IN HANDLE hHeap,
  752. IN DWORD dwFlags,
  753. IN LPVOID lpMem,
  754. IN SIZE_T dwBytes
  755. )
  756. {
  757. LPVOID p = ::HeapReAlloc(hHeap, dwFlags, lpMem, dwBytes);
  758. if (p == NULL)
  759. {
  760. ::SetLastError(FUSION_WIN32_ALLOCFAILED_ERROR);
  761. }
  762. return p;
  763. }
  764. #endif // FUSION_DEBUG_HEAP