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.

4100 lines
83 KiB

  1. /*
  2. - E X C H M E M . C
  3. -
  4. * Purpose:
  5. *
  6. *
  7. *
  8. *
  9. * Copyright (C) 1995-96, Microsoft Corporation.
  10. */
  11. #define _CRTIMP __declspec(dllexport)
  12. #include <malloc.h>
  13. #include <string.h>
  14. #include <stdio.h>
  15. #include <windows.h>
  16. #ifdef DEBUG
  17. #include <imagehlp.h>
  18. #endif
  19. #include <limits.h>
  20. #include <exchmem.h>
  21. #include "_exchmem.h"
  22. #include "excpt.h"
  23. #include "io.h"
  24. #ifndef DEBUG
  25. #define USEMPHEAP
  26. #endif
  27. #ifdef USEMPHEAP
  28. #include <mpheap.h>
  29. #endif
  30. // Global heap assigned to the process by NT
  31. HANDLE hProcessHeap = NULL;
  32. #ifdef USEMPHEAP
  33. HANDLE hMpHeap = NULL;
  34. ULONG cRefHeap = -1;
  35. #else
  36. LPHEAPTBL pheaptbl = NULL;
  37. CRITICAL_SECTION csMHeap;
  38. #endif
  39. DWORD tlsiHeapHint = 0;
  40. // Debug Support for leak detection and memory usage tracking.
  41. #ifdef DEBUG
  42. static HMODULE hMod;
  43. static HINSTANCE hinstRunTime = NULL;
  44. static BOOL fDbgEnable = FALSE;
  45. static BOOL fCallStacks = FALSE;
  46. static BOOL fSymInitialize = FALSE;
  47. static BOOL fProcessIsService = FALSE;
  48. static LPFMALLOC pfMalloc = NULL;
  49. static LPFREALLOC pfRealloc = NULL;
  50. static LPFFREE pfFree = NULL;
  51. static LPFCALLOC pfCalloc = NULL;
  52. static LPFSTRDUP pfStrDup = NULL;
  53. static LPFMEMSIZE pfMemSize = NULL;
  54. static BOOL fAssertLeaks = FALSE;
  55. static BOOL fDumpLeaks = FALSE;
  56. static BOOL fDumpLeaksDebugger = FALSE;
  57. static BOOL fUseVirtual = FALSE;
  58. static ULONG cbVirtualAlign = 1;
  59. static BOOL fFailuresEnabled = FALSE;
  60. static BOOL fHeapMonitorUI = FALSE;
  61. static BOOL fOverwriteDetect = FALSE;
  62. static BOOL fValidateMemory = FALSE;
  63. static BOOL fTrackFreedMemory = FALSE;
  64. static DWORD cEntriesFree = 512;
  65. static BOOL fAssertValid = FALSE;
  66. static BOOL fTrapOnInvalid = FALSE;
  67. static BOOL fSymbolLookup = FALSE;
  68. static BOOL fFillMemory = FALSE;
  69. static BYTE chAllocFillByte = chDefaultAllocFill;
  70. static BYTE chFreeFillByte = chDefaultFreeFill;
  71. static BOOL fTrackMem = FALSE;
  72. static DWORD cFrames = 0;
  73. static FILE * hTrackLog = NULL;
  74. static CRITICAL_SECTION csTrackLog;
  75. static char rgchExeName[16];
  76. static char rgchLogPath[MAX_PATH];
  77. BOOL fChangeTrackState = FALSE;
  78. static ULONG iAllocationFault = 0;
  79. #define NBUCKETS 8192
  80. #define UlHash(_n) ((ULONG)(((_n & 0x000FFFF0) >> 4) % NBUCKETS))
  81. typedef struct _symcache
  82. {
  83. DWORD_PTR dwAddress;
  84. DWORD_PTR dwOffset;
  85. CHAR rgchSymbol[248];
  86. } SYMCACHE, * PSYMCACHE;
  87. static PSYMCACHE rgsymcacheHashTable = NULL;
  88. static CRITICAL_SECTION csHeapList;
  89. static PHEAP pheapList = NULL;
  90. CHAR * PszGetSymbolFromCache(DWORD_PTR dwAddress, DWORD_PTR * pdwOffset);
  91. VOID AddSymbolToCache(DWORD_PTR dwAddress, DWORD_PTR dwOffset, CHAR * pszSymbol);
  92. BOOL FTrackMem();
  93. VOID StartTrace(BOOL fFresh);
  94. VOID StopTrace();
  95. typedef struct
  96. {
  97. WORD wApi;
  98. DWORD_PTR rgdwCallStack[32];
  99. DWORD_PTR rgdwArgs[5];
  100. DWORD dwTickCount;
  101. DWORD dwThreadId;
  102. } MEMTRACE;
  103. MEMTRACE * rgmemtrace = NULL;
  104. DWORD dwmemtrace = 0;
  105. DWORD dwTrackMemInMem = 0;
  106. #endif // DEBUG
  107. /*
  108. - DllMain
  109. -
  110. * Purpose:
  111. * Entry point called by CRT entry point.
  112. *
  113. */
  114. BOOL
  115. APIENTRY
  116. DllMain(
  117. HANDLE hModule,
  118. DWORD dwReason,
  119. LPVOID lpReserved)
  120. {
  121. if (dwReason == DLL_PROCESS_ATTACH)
  122. {
  123. DisableThreadLibraryCalls(hModule);
  124. #ifdef USEMPHEAP
  125. tlsiHeapHint = TlsAlloc();
  126. #else
  127. // Init the CS that protects access to the
  128. // global Multiple Heap data structs.
  129. InitializeCriticalSection(&csMHeap);
  130. // Now, if Debug build then do a lot of initialization
  131. // including creating a debug process heap. If not
  132. // Debug, then just get the ProcessHeap from system.
  133. #endif
  134. #ifdef DEBUG
  135. InitDebugExchMem(hModule);
  136. #else
  137. hProcessHeap = GetProcessHeap();
  138. #endif
  139. }
  140. else if (dwReason == DLL_PROCESS_DETACH)
  141. {
  142. #ifdef USEMPHEAP
  143. TlsFree(tlsiHeapHint);
  144. #else
  145. // Delete the Multiple Heap CS
  146. DeleteCriticalSection(&csMHeap);
  147. #endif
  148. // Tear-down our Debug support
  149. #ifdef DEBUG
  150. UnInitDebugExchMem();
  151. #endif
  152. }
  153. return TRUE;
  154. }
  155. //-----------------------------------------------------------------------------
  156. // The Handle based ExchMem APIs
  157. //-----------------------------------------------------------------------------
  158. HANDLE
  159. WINAPI
  160. ExchHeapCreate(
  161. DWORD dwFlags,
  162. DWORD dwInitialSize,
  163. DWORD dwMaxSize)
  164. {
  165. #ifndef DEBUG
  166. if (dwFlags & HEAP_NO_FREE)
  167. dwFlags &= ~(HEAP_NO_FREE);
  168. #endif
  169. return ExHeapCreate(dwFlags, dwInitialSize, dwMaxSize);
  170. }
  171. BOOL
  172. WINAPI
  173. ExchHeapDestroy(
  174. HANDLE hHeap)
  175. {
  176. return ExHeapDestroy(hHeap);
  177. }
  178. LPVOID
  179. WINAPI
  180. ExchHeapAlloc(
  181. HANDLE hHeap,
  182. DWORD dwFlags,
  183. DWORD dwSize)
  184. {
  185. return ExHeapAlloc(hHeap, dwFlags, dwSize);
  186. }
  187. LPVOID
  188. WINAPI
  189. ExchHeapReAlloc(
  190. HANDLE hHeap,
  191. DWORD dwFlags,
  192. LPVOID pvOld,
  193. DWORD dwSize)
  194. {
  195. if (!pvOld)
  196. return ExchHeapAlloc(hHeap, dwFlags, dwSize);
  197. return ExHeapReAlloc(hHeap, dwFlags, pvOld, dwSize);
  198. }
  199. BOOL
  200. WINAPI
  201. ExchHeapFree(
  202. HANDLE hHeap,
  203. DWORD dwFlags,
  204. LPVOID pvFree)
  205. {
  206. return ExHeapFree(hHeap, dwFlags, pvFree);
  207. }
  208. SIZE_T
  209. WINAPI
  210. ExchHeapCompact(
  211. HANDLE hHeap,
  212. DWORD dwFlags)
  213. {
  214. return ExHeapCompact(hHeap, dwFlags);
  215. }
  216. BOOL
  217. WINAPI
  218. ExchHeapLock(
  219. HANDLE hHeap)
  220. {
  221. return ExHeapLock(hHeap);
  222. }
  223. BOOL
  224. WINAPI
  225. ExchHeapUnlock(
  226. HANDLE hHeap)
  227. {
  228. return ExHeapUnlock(hHeap);
  229. }
  230. BOOL
  231. WINAPI
  232. ExchHeapWalk(
  233. HANDLE hHeap,
  234. LPPROCESS_HEAP_ENTRY lpEntry)
  235. {
  236. return ExHeapWalk(hHeap, lpEntry);
  237. }
  238. SIZE_T
  239. WINAPI
  240. ExchHeapSize(
  241. HANDLE hHeap,
  242. DWORD dwFlags,
  243. LPCVOID lpMem)
  244. {
  245. return ExHeapSize(hHeap, dwFlags, lpMem);
  246. }
  247. BOOL
  248. WINAPI
  249. ExchHeapValidate(
  250. HANDLE hHeap,
  251. DWORD dwFlags,
  252. LPCVOID lpMem)
  253. {
  254. return ExHeapValidate(hHeap, dwFlags, lpMem);
  255. }
  256. //-----------------------------------------------------------------------------
  257. // The Multiple Heap APIs
  258. //-----------------------------------------------------------------------------
  259. HANDLE
  260. WINAPI
  261. ExchMHeapCreate(
  262. ULONG cHeaps,
  263. DWORD dwFlags,
  264. DWORD dwInitialSize,
  265. DWORD dwMaxSize)
  266. {
  267. #ifndef USEMPHEAP
  268. HANDLE hheap0;
  269. HANDLE * phHeaps;
  270. ULONG iHeap;
  271. EnterCriticalSection(&csMHeap);
  272. // Called twice? The first person in gets to set the number
  273. // of heaps in the table. Subsequent calls result in an AddRef
  274. // to the current table and this table is returned to the caller.
  275. if (pheaptbl)
  276. {
  277. pheaptbl->cRef++;
  278. goto ret;
  279. }
  280. // If they didn't specify or they asked for too few then we'll set this
  281. if (cHeaps == 0)
  282. cHeaps = cHeapsDef;
  283. hheap0 = ExHeapCreate(dwFlags, dwInitialSize, dwMaxSize);
  284. if (!hheap0)
  285. {
  286. DebugTrace("Failed to create initial heap for MHeap APIs!\n");
  287. goto ret;
  288. }
  289. pheaptbl = (LPHEAPTBL)ExHeapAlloc(hheap0, 0,
  290. sizeof(HEAPTBL) + (cHeaps-1)*sizeof(HANDLE));
  291. if (!pheaptbl)
  292. {
  293. DebugTrace("Failed to allocate MHeap Table for MHeap APIs!\n");
  294. ExHeapDestroy(hheap0);
  295. goto ret;
  296. }
  297. memset(pheaptbl, 0, sizeof(HEAPTBL) + (cHeaps-1)*sizeof(HANDLE));
  298. pheaptbl->cRef = 1;
  299. pheaptbl->cHeaps = cHeaps;
  300. pheaptbl->rghheap[0] = hheap0;
  301. // Now, create the remaining heaps for the table.
  302. for (iHeap = 1, phHeaps = &pheaptbl->rghheap[1]; iHeap < cHeaps; iHeap++, phHeaps++)
  303. {
  304. if (!(*phHeaps = ExHeapCreate(dwFlags, dwInitialSize, dwMaxSize)))
  305. {
  306. DebugTrace("Failed to create additional heaps for MHeap APIs!\n");
  307. ExchMHeapDestroy();
  308. goto ret;
  309. }
  310. }
  311. ret:
  312. LeaveCriticalSection(&csMHeap);
  313. return (HANDLE)pheaptbl;
  314. #else
  315. // Called twice? The first person in gets to set the number
  316. // of heaps in the table. Subsequent calls result in an AddRef
  317. // to the current table and this table is returned to the caller.
  318. if (InterlockedIncrement(&cRefHeap) != 0)
  319. {
  320. Assert(hMpHeap);
  321. return hMpHeap;
  322. }
  323. else
  324. {
  325. //
  326. // NB: MpHeap doesn't support max size of heap.
  327. //
  328. return hMpHeap = MpHeapCreate(dwFlags, dwInitialSize, cHeaps);
  329. }
  330. #endif
  331. }
  332. BOOL
  333. WINAPI
  334. ExchMHeapDestroy(void)
  335. {
  336. #ifndef USEMPHEAP
  337. HANDLE hHeap;
  338. ULONG iHeap;
  339. EnterCriticalSection(&csMHeap);
  340. // If we are called too many times, we'll complain in the
  341. // Debug build, but otherwise, just return successfully!
  342. if (!pheaptbl)
  343. {
  344. DebugTrace("ExchMHeapDestroy called on invalid heap table!\n");
  345. goto ret;
  346. }
  347. // When our RefCount goes to zero, we tear-down the MHeap Table.
  348. if (--pheaptbl->cRef == 0)
  349. {
  350. for (iHeap = pheaptbl->cHeaps-1; iHeap > 0; iHeap-- )
  351. {
  352. if (hHeap = pheaptbl->rghheap[iHeap])
  353. ExHeapDestroy(hHeap);
  354. }
  355. hHeap = pheaptbl->rghheap[0];
  356. ExHeapFree(hHeap, 0, pheaptbl);
  357. ExHeapDestroy(hHeap);
  358. pheaptbl = NULL;
  359. }
  360. ret:
  361. LeaveCriticalSection(&csMHeap);
  362. return TRUE;
  363. #else
  364. BOOL fRet = 1;
  365. if (hMpHeap)
  366. {
  367. //
  368. // On last terminate blow away the heap.
  369. //
  370. if (InterlockedDecrement(&cRefHeap) < 0)
  371. {
  372. fRet = MpHeapDestroy(hMpHeap);
  373. hMpHeap = NULL;
  374. }
  375. }
  376. return fRet;
  377. #endif
  378. }
  379. //DWORD GetRetAddr(void)
  380. //{
  381. // DWORD * pdwStack;
  382. //
  383. // __asm mov pdwStack, ebp
  384. //
  385. // pdwStack = (DWORD *)*pdwStack;
  386. // pdwStack = (DWORD *)*pdwStack;
  387. //
  388. // return *(pdwStack + 1);
  389. //}
  390. LPVOID
  391. WINAPI
  392. ExchMHeapAlloc(
  393. DWORD dwSize)
  394. {
  395. #ifdef USEMPHEAP
  396. return MpHeapAlloc(hMpHeap, 0, dwSize);
  397. #else
  398. HANDLE hheap;
  399. LPVOID pv;
  400. hheap = pheaptbl->rghheap[GetCurrentThreadId() & (pheaptbl->cHeaps-1)];
  401. //Raid X5:195963 We never want to allocate/reallocate
  402. //less memory than what we have been requested.
  403. if (dwSize + cbMHeapHeader < dwSize) {
  404. DebugTrace("Trying to allocate a negative amount of memory!\n");
  405. return NULL;
  406. }
  407. pv = ExHeapAlloc(hheap, 0, dwSize + cbMHeapHeader);
  408. if (!pv)
  409. {
  410. DebugTrace("OOM: ExchMHeapAlloc failed to allocate a new block!\n");
  411. return NULL;
  412. }
  413. *(HANDLE *)pv = hheap;
  414. return MHeapPvFromPv(pv);
  415. #endif
  416. }
  417. LPVOID
  418. WINAPI
  419. ExchMHeapAllocDebug(
  420. DWORD dwSize, char *szFile, DWORD dwLine)
  421. {
  422. #ifdef USEMPHEAP
  423. return MpHeapAlloc(hMpHeap, 0, dwSize);
  424. #else
  425. HANDLE hheap;
  426. LPVOID pv;
  427. hheap = pheaptbl->rghheap[GetCurrentThreadId() & (pheaptbl->cHeaps-1)];
  428. //Raid X5:195963 We never want to allocate/reallocate
  429. //less memory than what we have been requested.
  430. if (dwSize + cbMHeapHeader < dwSize) {
  431. DebugTrace("Trying to allocate a negative amount of memory!\n");
  432. return NULL;
  433. }
  434. pv = ExHeapAlloc(hheap, 0, dwSize + cbMHeapHeader);
  435. if (!pv)
  436. {
  437. DebugTrace("OOM: ExchMHeapAlloc failed to allocate a new block!\n");
  438. return NULL;
  439. }
  440. *(HANDLE *)pv = hheap;
  441. if (fDbgEnable)
  442. {
  443. HeapSetName2(hheap, pv, "File: %s, Line: %d", szFile, dwLine);
  444. }
  445. return MHeapPvFromPv(pv);
  446. #endif
  447. }
  448. LPVOID
  449. WINAPI
  450. ExchMHeapReAlloc(
  451. LPVOID pvOld,
  452. DWORD dwSize)
  453. {
  454. #ifdef USEMPHEAP
  455. return MpHeapReAlloc(hMpHeap, pvOld, dwSize);
  456. #else
  457. LPVOID pv;
  458. //Raid X5:195963 We never want to allocate/reallocate
  459. //less memory than what we have been requested.
  460. if (dwSize + cbMHeapHeader < dwSize) {
  461. DebugTrace("Trying to allocate a negative amount of memory!\n");
  462. return NULL;
  463. }
  464. pv = ExHeapReAlloc(
  465. HandleFromMHeapPv(pvOld),
  466. 0,
  467. PvFromMHeapPv(pvOld),
  468. dwSize + cbMHeapHeader);
  469. if (!pv)
  470. {
  471. DebugTrace("OOM: ExchMHeapReAlloc failed to reallocate a block!\n");
  472. return NULL;
  473. }
  474. return MHeapPvFromPv(pv);
  475. #endif
  476. }
  477. LPVOID
  478. WINAPI
  479. ExchMHeapReAllocDebug(
  480. LPVOID pvOld,
  481. DWORD dwSize, char *szFile, DWORD dwLine)
  482. {
  483. #ifdef USEMPHEAP
  484. return MpHeapReAlloc(hMpHeap, pvOld, dwSize);
  485. #else
  486. LPVOID pv;
  487. //Raid X5:195963 We never want to allocate/reallocate
  488. //less memory than what we have been requested.
  489. if (dwSize + cbMHeapHeader < dwSize) {
  490. DebugTrace("Trying to allocate a negative amount of memory!\n");
  491. return NULL;
  492. }
  493. pv = ExHeapReAlloc(
  494. HandleFromMHeapPv(pvOld),
  495. 0,
  496. PvFromMHeapPv(pvOld),
  497. dwSize + cbMHeapHeader);
  498. if (!pv)
  499. {
  500. DebugTrace("OOM: ExchMHeapReAlloc failed to reallocate a block!\n");
  501. return NULL;
  502. }
  503. if (fDbgEnable)
  504. {
  505. HeapSetName2(HandleFromMHeapPv(MHeapPvFromPv(pv)), pv, "File: %s, Line: %d", szFile, dwLine);
  506. }
  507. return MHeapPvFromPv(pv);
  508. #endif
  509. }
  510. BOOL
  511. WINAPI
  512. ExchMHeapFree(
  513. LPVOID pvFree)
  514. {
  515. #ifdef USEMPHEAP
  516. if (pvFree)
  517. {
  518. return MpHeapFree(hMpHeap, pvFree);
  519. }
  520. else
  521. return FALSE;
  522. #else
  523. if (pvFree)
  524. {
  525. return ExHeapFree(
  526. HandleFromMHeapPv(pvFree),
  527. 0,
  528. PvFromMHeapPv(pvFree));
  529. }
  530. else
  531. return FALSE;
  532. #endif
  533. }
  534. SIZE_T
  535. WINAPI
  536. ExchMHeapSize(
  537. LPVOID pvSize)
  538. {
  539. if (pvSize)
  540. {
  541. #ifdef USEMPHEAP
  542. return MpHeapSize(hMpHeap, 0, pvSize);
  543. #else
  544. return ((ExHeapSize(
  545. HandleFromMHeapPv(pvSize),
  546. 0,
  547. PvFromMHeapPv(pvSize))) - cbMHeapHeader);
  548. #endif
  549. }
  550. else
  551. return 0;
  552. }
  553. //-----------------------------------------------------------------------------
  554. // The Heap Handle-less APIs
  555. //-----------------------------------------------------------------------------
  556. LPVOID
  557. WINAPI
  558. ExchAlloc(
  559. DWORD dwSize)
  560. {
  561. #ifdef DEBUG
  562. if (!hProcessHeap)
  563. {
  564. hProcessHeap = DebugHeapCreate(0, 0, 0);
  565. HeapSetHeapName(hProcessHeap, "Default ExchMem Heap");
  566. }
  567. #endif // DEBUG
  568. return ExHeapAlloc(hProcessHeap, 0, dwSize);
  569. }
  570. LPVOID
  571. WINAPI
  572. ExchReAlloc(
  573. LPVOID pvOld,
  574. DWORD dwSize)
  575. {
  576. if (!pvOld)
  577. return ExchAlloc(dwSize);
  578. return ExHeapReAlloc(hProcessHeap, 0, pvOld, dwSize);
  579. }
  580. BOOL
  581. WINAPI
  582. ExchFree(
  583. LPVOID pvFree)
  584. {
  585. return ExHeapFree(hProcessHeap, 0, pvFree);
  586. }
  587. SIZE_T
  588. WINAPI
  589. ExchSize(
  590. LPVOID pv)
  591. {
  592. #ifdef DEBUG
  593. if (!hProcessHeap)
  594. {
  595. hProcessHeap = DebugHeapCreate(0, 0, 0);
  596. HeapSetHeapName(hProcessHeap, "Default ExchMem Heap");
  597. }
  598. #endif // DEBUG
  599. return ExHeapSize(hProcessHeap, 0, pv);
  600. }
  601. //-----------------------------------------------------------------------------
  602. // All debug code starts here!
  603. //-----------------------------------------------------------------------------
  604. #ifdef DEBUG
  605. //-----------------------------------------------------------------------------
  606. // Implementaion of C-Runtimes that use malloc memory
  607. //-----------------------------------------------------------------------------
  608. static char szDebugIni[] = "EXCHMEM.INI";
  609. static char szSectionAppNames[] = "Apps To Track";
  610. static char szSectionHeap[] = "Memory Management";
  611. static char szKeyUseVirtual[] = "VirtualMemory";
  612. static char szKeyVirtualAlign[] = "VirtualAlign";
  613. static char szKeyAssertLeaks[] = "AssertLeaks";
  614. static char szKeyDumpLeaks[] = "DumpLeaks";
  615. static char szKeyDumpLeaksDebugger[]= "DumpLeaksToDebugger";
  616. static char szKeyFillMem[] = "FillMemory";
  617. static char szKeyAllocFillByte[] = "AllocFillByte";
  618. static char szKeyFreeFillByte[] = "FreeFillByte";
  619. static char szKeyTrackMem[] = "TrackMemory";
  620. static char szKeyTrackMemInMem[] = "TrackMemoryInMemory";
  621. static char szKeyStackFrames[] = "StackFrames";
  622. static char szKeySymbolLookup[] = "SymbolLookup";
  623. static char szKeyOverwriteDetect[] = "OverwriteDetect";
  624. static char szKeyValidateMemory[] = "ValidateMemory";
  625. static char szKeyTrackFreedMemory[] = "TrackFreedMemory";
  626. static char szKeyFreedMemorySize[] = "FreedMemorySize";
  627. static char szKeyAssertValid[] = "AssertValid";
  628. static char szKeyTrapOnInvalid[] = "TrapOnInvalid";
  629. static char szKeySymPath[] = "SymPath";
  630. static char szKeyLogPath[] = "LogPath";
  631. static char szSectionAF[] = "Heap Resource Failures";
  632. static char szKeyAFEnabled[] = "FailuresEnabled";
  633. static char szKeyAFStart[] = "AllocsToFirstFailure";
  634. static char szKeyAFInterval[] = "FailureInterval";
  635. static char szKeyAFBufSize[] = "FailureSize";
  636. static char szKeyHeapMon[] = "MonitorHeap";
  637. static char szHeapMonDLL[] = "GLHMON32.DLL";
  638. static char szHeapMonEntry[] = "HeapMonitor";
  639. static char szGetSymNameEntry[] = "GetSymbolName";
  640. static char szAllocationFault[] = "FaultingAllocationNumber";
  641. /*
  642. - InitDebugExchMem
  643. -
  644. * Purpose:
  645. *
  646. *
  647. * Parameters:
  648. *
  649. *
  650. * Returns:
  651. *
  652. */
  653. BOOL InitDebugExchMem(HMODULE hModule)
  654. {
  655. ULONG cch;
  656. char * pch;
  657. char rgchModulePath[MAX_PATH];
  658. // Get the executable name and search look in exchmem.ini
  659. // to see if we are interested in memory tracing for this
  660. // process. The ini section looks like this:
  661. //
  662. // [Apps To Track]
  663. // store=1
  664. // emsmta=0
  665. // dsamain=0
  666. //
  667. // etc. This sample specifies that only the store is to
  668. // be enabled for memory tracking.
  669. GetModuleFileName(NULL, rgchModulePath, MAX_PATH);
  670. RemoveExtension(rgchModulePath);
  671. pch = rgchModulePath + lstrlen(rgchModulePath) - 1;
  672. while (*pch != '\\' && pch >= rgchModulePath)
  673. pch--;
  674. lstrcpy(rgchExeName, ++pch);
  675. fDbgEnable = !!(BOOL)GetPrivateProfileIntA(szSectionAppNames,
  676. rgchExeName, 0, szDebugIni);
  677. // Store module handle in global var
  678. hMod = hModule;
  679. if (!hinstRunTime)
  680. {
  681. hinstRunTime = LoadLibrary("msvcrt.dll");
  682. if (!hinstRunTime)
  683. {
  684. DebugTrace("EXCHMEM: Failed to load the run-time dll!\n");
  685. return FALSE;
  686. }
  687. pfMalloc = (LPFMALLOC)GetProcAddress(hinstRunTime, "malloc");
  688. if (!pfMalloc)
  689. {
  690. DebugTrace("EXCHMEM: Failed to GetProcAddress of malloc in run-time dll!\n");
  691. FreeLibrary(hinstRunTime);
  692. return FALSE;
  693. }
  694. pfRealloc = (LPFREALLOC)GetProcAddress(hinstRunTime, "realloc");
  695. if (!pfRealloc)
  696. {
  697. DebugTrace("EXCHMEM: Failed to GetProcAddress of realloc in run-time dll!\n");
  698. FreeLibrary(hinstRunTime);
  699. return FALSE;
  700. }
  701. pfFree = (LPFFREE)GetProcAddress(hinstRunTime, "free");
  702. if (!pfFree)
  703. {
  704. DebugTrace("EXCHMEM: Failed to GetProcAddress of free in run-time dll!\n");
  705. FreeLibrary(hinstRunTime);
  706. return FALSE;
  707. }
  708. pfCalloc = (LPFCALLOC)GetProcAddress(hinstRunTime, "calloc");
  709. if (!pfCalloc)
  710. {
  711. DebugTrace("EXCHMEM: Failed to GetProcAddress of calloc in run-time dll!\n");
  712. FreeLibrary(hinstRunTime);
  713. return FALSE;
  714. }
  715. pfStrDup = (LPFSTRDUP)GetProcAddress(hinstRunTime, "_strdup");
  716. if (!pfStrDup)
  717. {
  718. DebugTrace("EXCHMEM: Failed to GetProcAddress of _strdup in run-time dll!\n");
  719. FreeLibrary(hinstRunTime);
  720. return FALSE;
  721. }
  722. pfMemSize = (LPFMEMSIZE)GetProcAddress(hinstRunTime, "_msize");
  723. if (!pfMemSize)
  724. {
  725. DebugTrace("EXCHMEM: Failed to GetProcAddress of _msize in run-time dll!\n");
  726. FreeLibrary(hinstRunTime);
  727. return FALSE;
  728. }
  729. }
  730. // Lookup symbols or just log addresses?
  731. fSymbolLookup = GetPrivateProfileIntA(szSectionHeap, szKeySymbolLookup, 0, szDebugIni);
  732. if (!fDbgEnable)
  733. {
  734. if (fSymbolLookup && !fSymInitialize)
  735. {
  736. char rgchSymPath[MAX_PATH];
  737. rgsymcacheHashTable = VirtualAlloc(
  738. NULL,
  739. NBUCKETS*sizeof(SYMCACHE),
  740. MEM_COMMIT,
  741. PAGE_READWRITE);
  742. if (rgsymcacheHashTable == NULL)
  743. {
  744. return FALSE;
  745. }
  746. GetPrivateProfileString(szSectionHeap,
  747. szKeySymPath,
  748. "c:\\exchsrvr\\bin;.",
  749. rgchSymPath,
  750. MAX_PATH-1,
  751. szDebugIni);
  752. {
  753. DWORD dwOptions;
  754. dwOptions = SymGetOptions();
  755. SymSetOptions(dwOptions | SYMOPT_DEFERRED_LOADS);
  756. }
  757. SymInitialize(GetCurrentProcess(), rgchSymPath, TRUE);
  758. fSymInitialize = TRUE;
  759. }
  760. goto ret;
  761. }
  762. // This CS protects access to a list of all live heaps
  763. InitializeCriticalSection(&csHeapList);
  764. // Initialize support for memory monitoring and leak detection
  765. fDumpLeaks = GetPrivateProfileIntA(szSectionHeap, szKeyDumpLeaks, 0, szDebugIni);
  766. fDumpLeaksDebugger = GetPrivateProfileIntA(szSectionHeap, szKeyDumpLeaksDebugger, 0, szDebugIni);
  767. fAssertLeaks = GetPrivateProfileIntA(szSectionHeap, szKeyAssertLeaks, 0, szDebugIni);
  768. fUseVirtual = GetPrivateProfileIntA(szSectionHeap, szKeyUseVirtual, 0, szDebugIni);
  769. if (fUseVirtual)
  770. cbVirtualAlign = GetPrivateProfileIntA(szSectionHeap, szKeyVirtualAlign, 1, szDebugIni);
  771. fFillMemory = GetPrivateProfileIntA(szSectionHeap, szKeyFillMem, 0, szDebugIni);
  772. if (fFillMemory)
  773. {
  774. char szFillByte[8];
  775. // Set the memory fill characters.
  776. if (GetPrivateProfileString(
  777. szSectionHeap,
  778. szKeyAllocFillByte,
  779. "", szFillByte,
  780. sizeof(szFillByte)-1,
  781. szDebugIni))
  782. chAllocFillByte = HexByteToBin(szFillByte);
  783. if (GetPrivateProfileString(
  784. szSectionHeap,
  785. szKeyFreeFillByte,
  786. "", szFillByte,
  787. sizeof(szFillByte)-1,
  788. szDebugIni))
  789. chFreeFillByte = HexByteToBin(szFillByte);
  790. }
  791. //$ISSUE
  792. // For now, just use virtual to detect overwrites!
  793. // Maybe I'll change this later to use pads on the
  794. // front and back side of a block. -RLS
  795. fOverwriteDetect = GetPrivateProfileIntA(szSectionHeap, szKeyOverwriteDetect, 0, szDebugIni);
  796. fValidateMemory = GetPrivateProfileIntA(szSectionHeap, szKeyValidateMemory, 0, szDebugIni);
  797. fTrackFreedMemory = GetPrivateProfileIntA(szSectionHeap, szKeyTrackFreedMemory, 0, szDebugIni);
  798. cEntriesFree = GetPrivateProfileIntA(szSectionHeap, szKeyFreedMemorySize, 512, szDebugIni);
  799. fAssertValid = GetPrivateProfileIntA(szSectionHeap, szKeyAssertValid, 0, szDebugIni);
  800. fTrapOnInvalid = GetPrivateProfileIntA(szSectionHeap, szKeyTrapOnInvalid, 0, szDebugIni);
  801. fHeapMonitorUI = GetPrivateProfileIntA(szSectionHeap, szKeyHeapMon, 0, szDebugIni);
  802. fFailuresEnabled = GetPrivateProfileIntA(szSectionAF, szKeyAFEnabled, 0, szDebugIni);
  803. // Get file path to write log files into
  804. GetPrivateProfileString(szSectionHeap,
  805. szKeyLogPath,
  806. ".\\",
  807. rgchLogPath,
  808. MAX_PATH-1,
  809. szDebugIni);
  810. cch = lstrlen(rgchLogPath);
  811. if (rgchLogPath[cch-1] != '\\')
  812. {
  813. rgchLogPath[cch] = '\\';
  814. rgchLogPath[cch+1] = '\0';
  815. }
  816. // Initialize support for memory usage tracking
  817. fTrackMem = GetPrivateProfileIntA(szSectionHeap, szKeyTrackMem, 0, szDebugIni);
  818. if (fTrackMem)
  819. StartTrace(TRUE);
  820. // This is for keeping track of the last x mem functions in a circular list in memory.
  821. // This doesn't slow things down as much as tracing everything to disk and can be useful
  822. // in finding memory problems that are timing related.
  823. dwTrackMemInMem = GetPrivateProfileIntA(szSectionHeap, szKeyTrackMemInMem, 0, szDebugIni);
  824. if (dwTrackMemInMem)
  825. {
  826. fTrackMem = TRUE;
  827. rgmemtrace = VirtualAlloc(
  828. NULL,
  829. dwTrackMemInMem*sizeof(MEMTRACE),
  830. MEM_COMMIT,
  831. PAGE_READWRITE);
  832. }
  833. // How many Stack Frames does the user want traced?
  834. cFrames = GetPrivateProfileIntA(szSectionHeap, szKeyStackFrames, 0, szDebugIni);
  835. if (cFrames > NSTK)
  836. cFrames = NSTK;
  837. // This is used in the debug build to determine if we will
  838. // allow the HeapMonitor UI or not. We do not allow it if
  839. // the process that is attaching to us is a service.
  840. fProcessIsService = IsProcessRunningAsService();
  841. // Initialize the symbols stuff for imagehlp.dll
  842. fCallStacks = (fDumpLeaks || fAssertLeaks || fTrackMem || fHeapMonitorUI || fValidateMemory);
  843. if (cFrames && fCallStacks && !fSymInitialize)
  844. {
  845. char rgchSymPath[MAX_PATH];
  846. rgsymcacheHashTable = VirtualAlloc(
  847. NULL,
  848. NBUCKETS*sizeof(SYMCACHE),
  849. MEM_COMMIT,
  850. PAGE_READWRITE);
  851. if (rgsymcacheHashTable == NULL)
  852. {
  853. return FALSE;
  854. }
  855. GetPrivateProfileString(szSectionHeap,
  856. szKeySymPath,
  857. "c:\\exchsrvr\\bin;.",
  858. rgchSymPath,
  859. MAX_PATH-1,
  860. szDebugIni);
  861. {
  862. DWORD dwOptions;
  863. dwOptions = SymGetOptions();
  864. SymSetOptions(dwOptions | SYMOPT_DEFERRED_LOADS);
  865. }
  866. SymInitialize(GetCurrentProcess(), rgchSymPath, TRUE);
  867. fSymInitialize = TRUE;
  868. }
  869. ret:
  870. return TRUE;
  871. }
  872. /*
  873. - UnInitDebugExchMem
  874. -
  875. * Purpose:
  876. *
  877. *
  878. * Parameters:
  879. *
  880. *
  881. * Returns:
  882. *
  883. */
  884. VOID UnInitDebugExchMem(VOID)
  885. {
  886. PHEAP pheap = pheapList;
  887. while (pheap)
  888. {
  889. if (fDumpLeaks && (pheap->ulFlags & HEAP_NO_FREE))
  890. HeapDumpLeaks(pheap, TRUE);
  891. pheap = pheap->pNext;
  892. }
  893. if (hProcessHeap)
  894. DebugHeapDestroy(hProcessHeap);
  895. if (hinstRunTime)
  896. {
  897. FreeLibrary(hinstRunTime);
  898. hinstRunTime = NULL;
  899. pfMalloc = NULL;
  900. pfRealloc = NULL;
  901. pfFree = NULL;
  902. pfCalloc = NULL;
  903. pfStrDup = NULL;
  904. pfMemSize = NULL;
  905. }
  906. if (fDbgEnable)
  907. {
  908. if (fSymInitialize)
  909. {
  910. VirtualFree(rgsymcacheHashTable, NBUCKETS*sizeof(SYMCACHE), MEM_DECOMMIT);
  911. VirtualFree(rgsymcacheHashTable, 0, MEM_RELEASE);
  912. SymCleanup(GetCurrentProcess());
  913. fSymInitialize = FALSE;
  914. }
  915. DeleteCriticalSection(&csHeapList);
  916. StopTrace();
  917. if (dwTrackMemInMem)
  918. {
  919. VirtualFree(rgmemtrace, dwTrackMemInMem*sizeof(MEMTRACE), MEM_DECOMMIT);
  920. VirtualFree(rgmemtrace, 0, MEM_RELEASE);
  921. }
  922. }
  923. }
  924. /*
  925. - calloc
  926. -
  927. * Purpose:
  928. * Replace the calloc() function supplied in the c-runtimes. Like
  929. * malloc() except zero fills the memory that is allocated.
  930. *
  931. * Parameters:
  932. * cStructs Number of objects the caller wants room for
  933. * cbStructs Size of an individual object
  934. *
  935. * Returns:
  936. * pv Pointer to zero filled memory of size: cStructs*cbStructs
  937. *
  938. */
  939. void *
  940. __cdecl
  941. calloc(
  942. size_t cStructs,
  943. size_t cbStructs)
  944. {
  945. void * pv;
  946. pv = pfCalloc(cStructs, cbStructs);
  947. if (fDbgEnable && FTrackMem())
  948. {
  949. DWORD_PTR rgdwArgs[4];
  950. DWORD_PTR rgdwCallers[NSTK];
  951. GetCallStack(rgdwCallers, cFrames);
  952. rgdwArgs[0] = (DWORD_PTR)0x00001000;
  953. rgdwArgs[1] = (DWORD_PTR)(cStructs*cbStructs);
  954. rgdwArgs[2] = (DWORD_PTR)pv;
  955. LogCurrentAPI(API_HEAP_ALLOC, rgdwCallers, cFrames, rgdwArgs, 3);
  956. }
  957. return pv;
  958. }
  959. /*
  960. - free
  961. -
  962. * Purpose:
  963. * To free memory allocated with malloc(0, realloc(), or calloc().
  964. *
  965. * Parameters:
  966. * pv Pointer to memory buffer to free
  967. *
  968. * Returns:
  969. * void
  970. *
  971. */
  972. void
  973. __cdecl
  974. free(
  975. void *pv)
  976. {
  977. if (fDbgEnable && FTrackMem())
  978. {
  979. DWORD_PTR rgdwArgs[4];
  980. DWORD_PTR rgdwCallers[NSTK];
  981. GetCallStack(rgdwCallers, cFrames);
  982. rgdwArgs[0] = (DWORD_PTR)0x00001000;
  983. rgdwArgs[1] = (DWORD_PTR)pv;
  984. rgdwArgs[2] = (pv ? (DWORD_PTR)pfMemSize(pv) : 0);
  985. LogCurrentAPI(API_HEAP_FREE, rgdwCallers, cFrames, rgdwArgs, 3);
  986. }
  987. pfFree(pv);
  988. }
  989. /*
  990. - malloc
  991. -
  992. * Purpose:
  993. * To allocate a memory buffer of size cb.
  994. *
  995. * Parameters:
  996. * cb Size of memory buffer to allocate
  997. *
  998. * Returns:
  999. * pv Pointer to memory buffer
  1000. *
  1001. */
  1002. void *
  1003. __cdecl
  1004. malloc(
  1005. size_t cb)
  1006. {
  1007. void * pv;
  1008. pv = pfMalloc(cb);
  1009. if (fDbgEnable && FTrackMem())
  1010. {
  1011. DWORD_PTR rgdwArgs[4];
  1012. DWORD_PTR rgdwCallers[NSTK];
  1013. GetCallStack(rgdwCallers, cFrames);
  1014. rgdwArgs[0] = (DWORD_PTR)0x00001000;
  1015. rgdwArgs[1] = (DWORD_PTR)cb;
  1016. rgdwArgs[2] = (DWORD_PTR)pv;
  1017. LogCurrentAPI(API_HEAP_ALLOC, rgdwCallers, cFrames, rgdwArgs, 3);
  1018. }
  1019. return pv;
  1020. }
  1021. /*
  1022. - realloc
  1023. -
  1024. * Purpose:
  1025. * To resize a memory buffer allocated with malloc().
  1026. *
  1027. * Parameters:
  1028. * pv Pointer to original memory buffer
  1029. * cb New size of memory buffer to be allocated
  1030. *
  1031. * Returns:
  1032. * pvNew Pointer to new memory buffer
  1033. *
  1034. */
  1035. void *
  1036. __cdecl
  1037. realloc(
  1038. void *pv,
  1039. size_t cb)
  1040. {
  1041. void * pvNew;
  1042. DWORD dwSize;
  1043. BOOL fTrackMem = FTrackMem();
  1044. if (fDbgEnable && fTrackMem)
  1045. dwSize = (pv ? pfMemSize(pv) : 0);
  1046. pvNew = pfRealloc(pv, cb);
  1047. if (fDbgEnable && fTrackMem)
  1048. {
  1049. DWORD_PTR rgdwArgs[5];
  1050. DWORD_PTR rgdwCallers[NSTK];
  1051. GetCallStack(rgdwCallers, cFrames);
  1052. rgdwArgs[0] = (DWORD_PTR)0x00001000;
  1053. rgdwArgs[1] = dwSize;
  1054. rgdwArgs[2] = (DWORD_PTR)pv;
  1055. rgdwArgs[3] = (DWORD_PTR)cb;
  1056. rgdwArgs[4] = (DWORD_PTR)pvNew;
  1057. LogCurrentAPI(API_HEAP_REALLOC, rgdwCallers, cFrames, rgdwArgs, 5);
  1058. }
  1059. return pvNew;
  1060. }
  1061. /*
  1062. - _strdup
  1063. -
  1064. * Purpose:
  1065. * To allocate a memory buffer large enough to hold sz, copy
  1066. * the contents of sz into the new buffer and return the new
  1067. * buffer to the caller (i.e. make a copy of the string).
  1068. *
  1069. * Parameters:
  1070. * sz Pointer to null terminated string to copy
  1071. *
  1072. * Returns:
  1073. * szNew Pointer to new copy of sz
  1074. *
  1075. */
  1076. char *
  1077. __cdecl
  1078. _strdup(
  1079. const char *sz)
  1080. {
  1081. return pfStrDup(sz);
  1082. }
  1083. //-----------------------------------------------------------------------------
  1084. // ExchMem Heap Debug Implementation
  1085. //-----------------------------------------------------------------------------
  1086. VOID
  1087. EnqueueHeap(PHEAP pheap)
  1088. {
  1089. EnterCriticalSection(&csHeapList);
  1090. if (pheapList)
  1091. pheap->pNext = pheapList;
  1092. pheapList = pheap;
  1093. LeaveCriticalSection(&csHeapList);
  1094. }
  1095. VOID
  1096. DequeueHeap(PHEAP pheap)
  1097. {
  1098. PHEAP pheapPrev = NULL;
  1099. PHEAP pheapCurr;
  1100. EnterCriticalSection(&csHeapList);
  1101. pheapCurr = pheapList;
  1102. while (pheapCurr)
  1103. {
  1104. if (pheapCurr == pheap)
  1105. break;
  1106. pheapPrev = pheapCurr;
  1107. pheapCurr = pheapCurr->pNext;
  1108. }
  1109. if (pheapCurr)
  1110. {
  1111. if (pheapPrev)
  1112. pheapPrev->pNext = pheapCurr->pNext;
  1113. else
  1114. pheapList = pheapCurr->pNext;
  1115. }
  1116. LeaveCriticalSection(&csHeapList);
  1117. }
  1118. HANDLE
  1119. WINAPI
  1120. DebugHeapCreate(
  1121. DWORD dwFlags,
  1122. DWORD dwInitialSize,
  1123. DWORD dwMaxSize)
  1124. {
  1125. HANDLE hDataHeap = 0;
  1126. HANDLE hBlksHeap = 0;
  1127. PHEAP pheap = NULL;
  1128. if (!fDbgEnable)
  1129. return HeapCreate(dwFlags, dwInitialSize, dwMaxSize);
  1130. // The first thing we must do is create a heap that we will
  1131. // allocate our Allocation Blocks on. We also allocate our
  1132. // debug Heap object on this heap.
  1133. hBlksHeap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
  1134. if (!hBlksHeap)
  1135. {
  1136. DebugTrace("HEAP_Open: Failed to create new heap!\n");
  1137. goto ret;
  1138. }
  1139. // Allocate the thing we hand back to the caller on this new heap.
  1140. pheap = HeapAlloc(hBlksHeap, 0, sizeof(HEAP));
  1141. if (!pheap)
  1142. {
  1143. DebugTrace("HEAP_Alloc: Failed to allocate heap handle!\n");
  1144. HeapDestroy(hBlksHeap);
  1145. hBlksHeap = NULL;
  1146. goto ret;
  1147. }
  1148. // Initialize all the goodies we store in this thing.
  1149. // Hook this heap into the global list of heaps we've
  1150. // created in this context.
  1151. memset(pheap, 0, sizeof(HEAP));
  1152. pheap->pfnSetName = (LPHEAPSETNAME)HeapSetNameFn;
  1153. pheap->hBlksHeap = hBlksHeap;
  1154. pheap->ulFlags = HEAP_LOCAL;
  1155. if (dwFlags & HEAP_NO_FREE)
  1156. {
  1157. pheap->ulFlags |= HEAP_NO_FREE;
  1158. dwFlags &= ~(HEAP_NO_FREE);
  1159. }
  1160. InitializeCriticalSection(&pheap->cs);
  1161. // VirtualMemory default is FALSE
  1162. if (fUseVirtual)
  1163. {
  1164. pheap->ulFlags |= HEAP_USE_VIRTUAL;
  1165. // We always want virtual allocations on RISC to be 4-byte aligned
  1166. // because all our code assumes that the beginning of an allocation
  1167. // is aligned on machine word boundaries. On other platforms,
  1168. // changing this behavior is non-fatal, but on RISC platforms we'll
  1169. // get alignment faults everywhere.
  1170. #if defined(_X86_)
  1171. if (cbVirtualAlign == 4)
  1172. #else
  1173. cbVirtualAlign = 4;
  1174. #endif
  1175. pheap->ulFlags |= HEAP_USE_VIRTUAL_4;
  1176. }
  1177. // DumpLeaks default is TRUE
  1178. if (fDumpLeaks)
  1179. pheap->ulFlags |= HEAP_DUMP_LEAKS;
  1180. // AssertLeaks default is FALSE
  1181. if (fAssertLeaks)
  1182. pheap->ulFlags |= HEAP_ASSERT_LEAKS;
  1183. // FillMem default is TRUE
  1184. if (fFillMemory)
  1185. {
  1186. pheap->ulFlags |= HEAP_FILL_MEM;
  1187. pheap->chFill = chAllocFillByte;
  1188. }
  1189. // Set up artificial failures. If anything is set in our ini file, then
  1190. // HEAP_FAILURES_ENABLED gets set.
  1191. if (fFailuresEnabled)
  1192. {
  1193. pheap->ulFlags |= HEAP_FAILURES_ENABLED;
  1194. pheap->ulFailStart = (ULONG)GetPrivateProfileInt(szSectionAF,
  1195. szKeyAFStart, 0, szDebugIni);
  1196. pheap->ulFailInterval = (ULONG)GetPrivateProfileInt(szSectionAF,
  1197. szKeyAFInterval, 0, szDebugIni);
  1198. pheap->ulFailBufSize = (ULONG)GetPrivateProfileInt(szSectionAF,
  1199. szKeyAFBufSize, 0, szDebugIni);
  1200. pheap->iAllocationFault = GetPrivateProfileIntA(szSectionAF,
  1201. szAllocationFault, 0, szDebugIni);
  1202. }
  1203. // If the user wants Heap Monitor UI, the spin a thread to manage a
  1204. // DialogBox that can display the status of the heap at all times.
  1205. if (fHeapMonitorUI && !fProcessIsService)
  1206. if (FRegisterHeap(pheap))
  1207. pheap->ulFlags |= HEAP_HEAP_MONITOR;
  1208. // If we are not using virtual memory allocators, then we
  1209. // create another heap to allocate the users data in.
  1210. if (!fUseVirtual)
  1211. {
  1212. hDataHeap = HeapCreate(dwFlags, dwInitialSize, dwMaxSize);
  1213. if (!hDataHeap)
  1214. {
  1215. DebugTrace("HeapAlloc: Failed to allocate heap handle!\n");
  1216. HeapDestroy(hBlksHeap);
  1217. pheap = NULL;
  1218. goto ret;
  1219. }
  1220. pheap->hDataHeap = hDataHeap;
  1221. }
  1222. // Name heap
  1223. HeapSetHeapName1(pheap, "ExchMem Heap: %08lX", pheap);
  1224. // Remove heap from list
  1225. EnqueueHeap(pheap);
  1226. if (FTrackMem())
  1227. {
  1228. DWORD_PTR rgdwArgs[4];
  1229. DWORD_PTR rgdwCallers[NSTK];
  1230. GetCallStack(rgdwCallers, cFrames);
  1231. rgdwArgs[0] = dwInitialSize;
  1232. rgdwArgs[1] = dwMaxSize;
  1233. rgdwArgs[2] = (DWORD_PTR)hDataHeap;
  1234. LogCurrentAPI(API_HEAP_CREATE, rgdwCallers, cFrames, rgdwArgs, 3);
  1235. }
  1236. ret:
  1237. return (HANDLE)pheap;
  1238. }
  1239. BOOL
  1240. WINAPI
  1241. DebugHeapDestroy(
  1242. HANDLE hHeap)
  1243. {
  1244. PHEAP pheap = (PHEAP)hHeap;
  1245. HANDLE hDataHeap = pheap->hDataHeap;
  1246. HANDLE hBlksHeap = pheap->hBlksHeap;
  1247. if (!fDbgEnable)
  1248. return HeapDestroy(hHeap);
  1249. // Remove heap from list
  1250. DequeueHeap(pheap);
  1251. // Dump memory leaks if we're supposed to.
  1252. if (fDumpLeaks && !(pheap->ulFlags & HEAP_NO_FREE))
  1253. HeapDumpLeaks(pheap, FALSE);
  1254. //
  1255. // Free the entries in the free list.
  1256. //
  1257. // This isn't totally necessary, since destroying the heap destroys the free list, but what the
  1258. // heck, it's cleaner to do it this way.
  1259. //
  1260. while (pheap->phblkFree)
  1261. {
  1262. PHBLK phblk = pheap->phblkFree;
  1263. pheap->phblkFree = phblk->phblkFreeNext;
  1264. //
  1265. // And now free up the block for real, it's too old.
  1266. //
  1267. if (fUseVirtual)
  1268. VMFreeEx((fOverwriteDetect ? PvHeadFromPv(phblk->pv) : phblk->pv), cbVirtualAlign);
  1269. else
  1270. HeapFree(pheap->hDataHeap, 0,
  1271. (fOverwriteDetect ? PvHeadFromPv(phblk->pv) : phblk->pv));
  1272. HeapFree(pheap->hBlksHeap, 0, phblk);
  1273. }
  1274. // Destroy the HeapMonitor thread and un-load the DLL
  1275. UnRegisterHeap(pheap);
  1276. if (fHeapMonitorUI && pheap->hInstHeapMon)
  1277. FreeLibrary(pheap->hInstHeapMon);
  1278. DeleteCriticalSection(&pheap->cs);
  1279. // Clean-up and leave. Closing frees leaks, so we're cool!
  1280. if (!fUseVirtual && hDataHeap)
  1281. {
  1282. HeapDestroy(hDataHeap);
  1283. }
  1284. if (hBlksHeap)
  1285. {
  1286. HeapFree(hBlksHeap, 0, pheap);
  1287. HeapDestroy(hBlksHeap);
  1288. }
  1289. if (FTrackMem())
  1290. {
  1291. DWORD_PTR rgdwArgs[4];
  1292. DWORD_PTR rgdwCallers[NSTK];
  1293. GetCallStack(rgdwCallers, cFrames);
  1294. rgdwArgs[0] = (DWORD_PTR)hDataHeap;
  1295. LogCurrentAPI(API_HEAP_DESTROY, rgdwCallers, cFrames, rgdwArgs, 1);
  1296. }
  1297. return TRUE;
  1298. }
  1299. LPVOID
  1300. WINAPI
  1301. DebugHeapAlloc(
  1302. HANDLE hHeap,
  1303. DWORD dwFlags,
  1304. DWORD dwSize)
  1305. {
  1306. PHEAP pheap = (PHEAP)hHeap;
  1307. PHBLK phblk = NULL;
  1308. LPVOID pvAlloc = NULL;
  1309. if (!fDbgEnable)
  1310. return HeapAlloc(hHeap, dwFlags, dwSize);
  1311. // Note: To be consistent with other (e.g. system) allocators,
  1312. // we have to return a valid allocation if dwSize == 0. So, we
  1313. // allow a dwSize of 0 to actually be allocated. (See bug 3556 in
  1314. // the sqlguest:exchange database.)
  1315. EnterCriticalSection(&pheap->cs);
  1316. if (fFailuresEnabled)
  1317. {
  1318. if (pheap->ulAllocNum == pheap->iAllocationFault)
  1319. {
  1320. DebugTrace("HeapRealloc: Allocation Fault hit\n");
  1321. DebugBreak();
  1322. }
  1323. if (FForceFailure(pheap, dwSize))
  1324. {
  1325. DebugTrace("HeapAlloc: Artificial Failure\n");
  1326. pvAlloc = NULL;
  1327. pheap->ulAllocNum++;
  1328. LeaveCriticalSection(&pheap->cs);
  1329. goto ret;
  1330. }
  1331. }
  1332. // We have to leave the CS before calling HeapAlloc in case the user
  1333. // created this heap with the HEAP_GENERATE_EXCEPTIONS flag set, which,
  1334. // if thrown, would cause us to exit here with our CS held - a bad thing...
  1335. LeaveCriticalSection(&pheap->cs);
  1336. if (fUseVirtual)
  1337. pvAlloc = VMAllocEx((fOverwriteDetect ? (dwSize + 2*cbOWSection) : dwSize), cbVirtualAlign);
  1338. else
  1339. pvAlloc = HeapAlloc(pheap->hDataHeap, dwFlags,
  1340. (fOverwriteDetect ? (dwSize + 2*cbOWSection) : dwSize));
  1341. // Now, re-aquire the CS and finish our work. We do not create the
  1342. // BlksHeap with the HEAP_GENERATE_EXCEPTIONS flag so we're cool.
  1343. EnterCriticalSection(&pheap->cs);
  1344. if (pvAlloc)
  1345. {
  1346. phblk = (PHBLK)HeapAlloc(pheap->hBlksHeap, 0, sizeof(HBLK));
  1347. if (phblk)
  1348. {
  1349. if (fOverwriteDetect)
  1350. {
  1351. // Fill the Head and Tail overwrite detection
  1352. // blocks special fill character: 0xAB.
  1353. memset(pvAlloc,
  1354. chOWFill,
  1355. cbOWSection);
  1356. memset(PvTailFromPvHead(pvAlloc, dwSize),
  1357. chOWFill,
  1358. cbOWSection);
  1359. // Now, advance pvAlloc to user portion of buffer
  1360. pvAlloc = PvFromPvHead(pvAlloc);
  1361. }
  1362. phblk->pheap = pheap;
  1363. phblk->szName[0] = '\0';
  1364. phblk->ulSize = dwSize;
  1365. phblk->ulAllocNum = ++pheap->ulAllocNum;
  1366. phblk->pv = pvAlloc;
  1367. phblk->phblkPrev = NULL;
  1368. phblk->phblkNext = NULL;
  1369. phblk->phblkFreeNext= NULL;
  1370. ZeroMemory(phblk->rgdwCallers, cFrames*sizeof(DWORD));
  1371. ZeroMemory(phblk->rgdwFree, cFrames*sizeof(DWORD));
  1372. PhblkEnqueue(phblk);
  1373. if (fCallStacks)
  1374. GetCallStack(phblk->rgdwCallers, cFrames);
  1375. if (fFillMemory && !(dwFlags & HEAP_ZERO_MEMORY))
  1376. memset(pvAlloc, pheap->chFill, (size_t)dwSize);
  1377. if (FTrackMem())
  1378. {
  1379. DWORD_PTR rgdwArgs[4];
  1380. rgdwArgs[0] = (DWORD_PTR)pheap->hDataHeap;
  1381. rgdwArgs[1] = dwSize;
  1382. rgdwArgs[2] = (DWORD_PTR)pvAlloc;
  1383. LogCurrentAPI(API_HEAP_ALLOC, phblk->rgdwCallers, cFrames, rgdwArgs, 3);
  1384. }
  1385. }
  1386. else
  1387. {
  1388. if (fUseVirtual)
  1389. VMFreeEx(pvAlloc, cbVirtualAlign);
  1390. else
  1391. HeapFree(pheap->hDataHeap, dwFlags, pvAlloc);
  1392. pvAlloc = NULL;
  1393. }
  1394. }
  1395. LeaveCriticalSection(&pheap->cs);
  1396. ret:
  1397. return pvAlloc;
  1398. }
  1399. LPVOID
  1400. WINAPI
  1401. DebugHeapReAlloc(
  1402. HANDLE hHeap,
  1403. DWORD dwFlags,
  1404. LPVOID pvOld,
  1405. DWORD dwSize)
  1406. {
  1407. PHEAP pheap = (PHEAP)hHeap;
  1408. LPVOID pvNew = NULL;
  1409. PHBLK phblk;
  1410. UINT cbOld;
  1411. if (!fDbgEnable)
  1412. return HeapReAlloc(hHeap, dwFlags, pvOld, dwSize);
  1413. if (pvOld == 0)
  1414. {
  1415. pvNew = DebugHeapAlloc(hHeap, dwFlags, dwSize);
  1416. }
  1417. else
  1418. {
  1419. EnterCriticalSection(&pheap->cs);
  1420. if (fValidateMemory)
  1421. {
  1422. if (!HeapValidatePv(pheap, pvOld, "DebugHeapReAlloc"))
  1423. {
  1424. LeaveCriticalSection(&pheap->cs);
  1425. goto ret;
  1426. }
  1427. }
  1428. phblk = PvToPhblk(pheap, pvOld);
  1429. cbOld = (UINT)CbPhblkClient(phblk);
  1430. PhblkDequeue(phblk);
  1431. // We have to leave the CS before calling HeapReAlloc in case the user
  1432. // created this heap with the HEAP_GENERATE_EXCEPTIONS flag set, which,
  1433. // if thrown, would cause us to exit here with our CS held - a bad thing...
  1434. LeaveCriticalSection(&pheap->cs);
  1435. if (fFailuresEnabled && pheap->ulAllocNum >= pheap->iAllocationFault)
  1436. {
  1437. DebugTrace("HeapRealloc: Allocation Fault hit\n");
  1438. DebugBreak();
  1439. }
  1440. else if (fFailuresEnabled && FForceFailure(pheap, dwSize) && (dwSize > cbOld))
  1441. {
  1442. InterlockedIncrement((LPLONG)&pheap->ulAllocNum);
  1443. pvNew = 0;
  1444. DebugTrace("HeapRealloc: Artificial Failure\n");
  1445. }
  1446. else if (fUseVirtual)
  1447. pvNew = VMReallocEx(fOverwriteDetect ? PvHeadFromPv(pvOld) : pvOld,
  1448. (fOverwriteDetect ? (dwSize + 2*cbOWSection) : dwSize),
  1449. cbVirtualAlign);
  1450. else
  1451. pvNew = HeapReAlloc(pheap->hDataHeap, dwFlags,
  1452. (fOverwriteDetect ? PvHeadFromPv(pvOld) : pvOld),
  1453. (fOverwriteDetect ? (dwSize + 2*cbOWSection) : dwSize));
  1454. // Now, re-aquire the CS and finish our work.
  1455. EnterCriticalSection(&pheap->cs);
  1456. if (pvNew)
  1457. {
  1458. if (fOverwriteDetect)
  1459. {
  1460. // Fill the Head and Tail overwrite detection
  1461. // blocks special fill character: 0xAB.
  1462. memset(pvNew,
  1463. chOWFill,
  1464. cbOWSection);
  1465. memset(PvTailFromPvHead(pvNew, dwSize),
  1466. chOWFill,
  1467. cbOWSection);
  1468. // Now, advance pvNew to user portion of buffer
  1469. pvNew = PvFromPvHead(pvNew);
  1470. }
  1471. if (fCallStacks)
  1472. GetCallStack(phblk->rgdwCallers, cFrames);
  1473. if (fFillMemory && (dwSize > cbOld) && !(dwFlags & HEAP_ZERO_MEMORY))
  1474. memset((LPBYTE)pvNew + cbOld, pheap->chFill, dwSize - cbOld);
  1475. phblk->pv = pvNew;
  1476. phblk->ulSize = dwSize;
  1477. phblk->ulAllocNum = ++pheap->ulAllocNum;
  1478. phblk->phblkPrev = NULL;
  1479. phblk->phblkNext = NULL;
  1480. phblk->phblkFreeNext= NULL;
  1481. }
  1482. else
  1483. {
  1484. phblk->phblkPrev = NULL;
  1485. phblk->phblkNext = NULL;
  1486. phblk->phblkFreeNext= NULL;
  1487. }
  1488. PhblkEnqueue(phblk);
  1489. if (FTrackMem())
  1490. {
  1491. DWORD_PTR rgdwArgs[5];
  1492. rgdwArgs[0] = (DWORD_PTR)pheap->hDataHeap;
  1493. rgdwArgs[1] = (DWORD_PTR)cbOld;
  1494. rgdwArgs[2] = (DWORD_PTR)pvOld;
  1495. rgdwArgs[3] = dwSize;
  1496. rgdwArgs[4] = (DWORD_PTR)pvNew;
  1497. LogCurrentAPI(API_HEAP_REALLOC, phblk->rgdwCallers, cFrames, rgdwArgs, 5);
  1498. }
  1499. LeaveCriticalSection(&pheap->cs);
  1500. }
  1501. ret:
  1502. return pvNew;
  1503. }
  1504. PHBLK
  1505. PhblkSearchFreeList(PHEAP pheap, LPVOID pv)
  1506. {
  1507. PHBLK phblkT = pheap->phblkFree;
  1508. //
  1509. // Walk the free list looking for this block, and if we find it, free it.
  1510. //
  1511. while (phblkT != NULL)
  1512. {
  1513. if (phblkT->pv == pv)
  1514. {
  1515. return phblkT;
  1516. }
  1517. phblkT = phblkT->phblkFreeNext;
  1518. }
  1519. return NULL;
  1520. }
  1521. BOOL
  1522. WINAPI
  1523. DebugHeapFree(
  1524. HANDLE hHeap,
  1525. DWORD dwFlags,
  1526. LPVOID pvFree)
  1527. {
  1528. PHEAP pheap = (PHEAP)hHeap;
  1529. BOOL fRet = TRUE;
  1530. DWORD dwSize = 0;
  1531. if (!fDbgEnable)
  1532. return HeapFree(hHeap, dwFlags, pvFree);
  1533. EnterCriticalSection(&pheap->cs);
  1534. //
  1535. // If we're tracking freed memory, then we don't actually free the blocks, we remember where they
  1536. // are on the freed block list.
  1537. //
  1538. if (pvFree)
  1539. {
  1540. PHBLK phblk;
  1541. phblk = PvToPhblk(pheap, pvFree);
  1542. dwSize = (size_t)CbPhblkClient(phblk);
  1543. if (!fValidateMemory || HeapValidatePv(pheap, pvFree, "DebugHeapFree"))
  1544. {
  1545. //
  1546. // remove this phblk from the list of allocated blocks - as far as the heap is concerned, it's
  1547. // no longer allocated.
  1548. //
  1549. PhblkDequeue(phblk);
  1550. //
  1551. // And fill the block with the free block pattern if appropriate.
  1552. //
  1553. if (fFillMemory)
  1554. {
  1555. memset(pvFree, chFreeFillByte, dwSize);
  1556. }
  1557. if (fTrackFreedMemory)
  1558. {
  1559. PHBLK phblkT;
  1560. if (fCallStacks)
  1561. GetCallStack(phblk->rgdwFree, cFrames);
  1562. //
  1563. // Now insert this free block onto the head of the free block list
  1564. //
  1565. phblkT = pheap->phblkFree;
  1566. pheap->phblkFree = phblk;
  1567. phblk->phblkFreeNext = phblkT;
  1568. //
  1569. // And then check to see if we have "too many" free entries.
  1570. //
  1571. if (++pheap->cEntriesFree > cEntriesFree)
  1572. {
  1573. PHBLK *phblkPrev = &pheap->phblkFree;
  1574. //
  1575. // There are too many entries on the free list, so we need to remove the last one.
  1576. //
  1577. phblkT = pheap->phblkFree;
  1578. while (phblkT->phblkFreeNext != NULL)
  1579. {
  1580. phblkPrev = &phblkT->phblkFreeNext;
  1581. phblkT = phblkT->phblkFreeNext;
  1582. }
  1583. Assert(*phblkPrev);
  1584. *phblkPrev = NULL;
  1585. //
  1586. // And now free up the block for real, it's too old.
  1587. //
  1588. if (fUseVirtual)
  1589. VMFreeEx((fOverwriteDetect ? PvHeadFromPv(phblkT->pv) : phblkT->pv), cbVirtualAlign);
  1590. else
  1591. fRet = HeapFree(pheap->hDataHeap, dwFlags,
  1592. (fOverwriteDetect ? PvHeadFromPv(phblkT->pv) : phblkT->pv));
  1593. HeapFree(pheap->hBlksHeap, 0, phblkT);
  1594. }
  1595. }
  1596. else // We're not tracking freed memory, so we can really free the memory right now.
  1597. {
  1598. //
  1599. // And now free up the block for real.
  1600. //
  1601. if (fUseVirtual)
  1602. VMFreeEx((fOverwriteDetect ? PvHeadFromPv(pvFree) : pvFree), cbVirtualAlign);
  1603. else
  1604. fRet = HeapFree(pheap->hDataHeap, dwFlags,
  1605. (fOverwriteDetect ? PvHeadFromPv(pvFree) : pvFree));
  1606. HeapFree(pheap->hBlksHeap, 0, phblk);
  1607. }
  1608. }
  1609. }
  1610. if (FTrackMem())
  1611. {
  1612. DWORD_PTR rgdwArgs[4];
  1613. DWORD_PTR rgdwCallers[NSTK];
  1614. GetCallStack(rgdwCallers, cFrames);
  1615. rgdwArgs[0] = (DWORD_PTR)pheap->hDataHeap;
  1616. rgdwArgs[1] = (DWORD_PTR)pvFree;
  1617. rgdwArgs[2] = dwSize;
  1618. LogCurrentAPI(API_HEAP_FREE, rgdwCallers, cFrames, rgdwArgs, 3);
  1619. }
  1620. LeaveCriticalSection(&pheap->cs);
  1621. return fRet;
  1622. }
  1623. BOOL
  1624. WINAPI
  1625. DebugHeapLock(
  1626. HANDLE hHeap)
  1627. {
  1628. PHEAP pheap = (PHEAP)hHeap;
  1629. if (!fDbgEnable)
  1630. return HeapLock(hHeap);
  1631. EnterCriticalSection(&pheap->cs);
  1632. return HeapLock(pheap->hDataHeap);
  1633. }
  1634. BOOL
  1635. WINAPI
  1636. DebugHeapUnlock(
  1637. HANDLE hHeap)
  1638. {
  1639. BOOL fRet;
  1640. PHEAP pheap = (PHEAP)hHeap;
  1641. if (!fDbgEnable)
  1642. return HeapUnlock(hHeap);
  1643. fRet = HeapUnlock(pheap->hDataHeap);
  1644. LeaveCriticalSection(&pheap->cs);
  1645. return fRet;
  1646. }
  1647. BOOL
  1648. WINAPI
  1649. DebugHeapWalk(
  1650. HANDLE hHeap,
  1651. LPPROCESS_HEAP_ENTRY lpEntry)
  1652. {
  1653. BOOL fRet;
  1654. PHEAP pheap = (PHEAP)hHeap;
  1655. if (!fDbgEnable)
  1656. return HeapWalk(hHeap, lpEntry);
  1657. EnterCriticalSection(&pheap->cs);
  1658. fRet = HeapWalk(pheap->hDataHeap, lpEntry);
  1659. LeaveCriticalSection(&pheap->cs);
  1660. return fRet;
  1661. }
  1662. BOOL
  1663. WINAPI
  1664. DebugHeapValidate(
  1665. HANDLE hHeap,
  1666. DWORD dwFlags,
  1667. LPCVOID lpMem)
  1668. {
  1669. BOOL fRet = TRUE;
  1670. PHEAP pheap = (PHEAP)hHeap;
  1671. if (!fDbgEnable)
  1672. return HeapValidate(hHeap, dwFlags, lpMem);
  1673. EnterCriticalSection(&pheap->cs);
  1674. if (!fUseVirtual)
  1675. fRet = HeapValidate(pheap->hDataHeap, dwFlags,
  1676. (lpMem != NULL && fOverwriteDetect ? PvHeadFromPv(lpMem) : lpMem));
  1677. LeaveCriticalSection(&pheap->cs);
  1678. return fRet;
  1679. }
  1680. SIZE_T
  1681. WINAPI
  1682. DebugHeapSize(
  1683. HANDLE hHeap,
  1684. DWORD dwFlags,
  1685. LPCVOID lpMem)
  1686. {
  1687. PHEAP pheap = (PHEAP)hHeap;
  1688. SIZE_T cb = 0;
  1689. if (!fDbgEnable)
  1690. return HeapSize(hHeap, dwFlags, lpMem);
  1691. EnterCriticalSection(&pheap->cs);
  1692. if ((fValidateMemory ? HeapValidatePv(pheap, (LPVOID)lpMem, "DebugHeapSize") : 1))
  1693. {
  1694. if (fUseVirtual)
  1695. {
  1696. cb = (UINT)VMGetSizeEx((LPVOID)lpMem, cbVirtualAlign);
  1697. }
  1698. else
  1699. {
  1700. cb = HeapSize(pheap->hDataHeap, dwFlags,
  1701. (fOverwriteDetect ? PvHeadFromPv(lpMem) : lpMem));
  1702. }
  1703. if (fOverwriteDetect)
  1704. {
  1705. cb -= 2*cbOWSection;
  1706. }
  1707. }
  1708. LeaveCriticalSection(&pheap->cs);
  1709. return cb;
  1710. }
  1711. SIZE_T
  1712. WINAPI
  1713. DebugHeapCompact(
  1714. HANDLE hHeap,
  1715. DWORD dwFlags)
  1716. {
  1717. PHEAP pheap = (PHEAP)hHeap;
  1718. SIZE_T cbLargestFreeBlk = 0;
  1719. if (!fDbgEnable)
  1720. return HeapCompact(hHeap, dwFlags);
  1721. EnterCriticalSection(&pheap->cs);
  1722. if (!fUseVirtual)
  1723. cbLargestFreeBlk = HeapCompact(pheap->hDataHeap, dwFlags);
  1724. LeaveCriticalSection(&pheap->cs);
  1725. return cbLargestFreeBlk;
  1726. }
  1727. //-----------------------------------------------------------------------------
  1728. // Debug Support routines
  1729. //-----------------------------------------------------------------------------
  1730. /*
  1731. - FRegisterHeap
  1732. -
  1733. * Purpose:
  1734. * If the user wants to monitor the Heap, then load the DLL with
  1735. * the HeapMonitor UI.
  1736. */
  1737. BOOL FRegisterHeap(PHEAP pheap)
  1738. {
  1739. HINSTANCE hInst;
  1740. LPHEAPMONPROC pfnHeapMon;
  1741. LPGETSYMNAMEPROC pfnGetSymName;
  1742. pheap->hInstHeapMon = 0;
  1743. pheap->pfnGetSymName = NULL;
  1744. hInst = LoadLibrary(szHeapMonDLL);
  1745. if (!hInst)
  1746. {
  1747. DebugTrace("FRegisterHeap: Failed to LoadLibrary GLHMON32.DLL.\n");
  1748. goto ret;
  1749. }
  1750. pfnHeapMon = (LPHEAPMONPROC)GetProcAddress(hInst, szHeapMonEntry);
  1751. if (!pfnHeapMon)
  1752. {
  1753. DebugTrace("FRegisterHeap: Failed to GetProcAddress of HeapMonitor.\n");
  1754. FreeLibrary(hInst);
  1755. goto ret;
  1756. }
  1757. pfnGetSymName = (LPGETSYMNAMEPROC)GetProcAddress(hInst, szGetSymNameEntry);
  1758. if (!pfnGetSymName)
  1759. {
  1760. DebugTrace("FRegisterHeap: Failed to GetProcAddress of GetSymName.\n");
  1761. }
  1762. pheap->hInstHeapMon = hInst;
  1763. if (!pfnHeapMon(pheap, HEAPMON_LOAD))
  1764. {
  1765. DebugTrace("FRegisterHeap: Call to HeapMonitor failed.\n");
  1766. pheap->hInstHeapMon = 0;
  1767. goto ret;
  1768. }
  1769. pheap->pfnHeapMon = pfnHeapMon;
  1770. pheap->pfnGetSymName = pfnGetSymName;
  1771. ret:
  1772. return (pheap->hInstHeapMon ? TRUE : FALSE);
  1773. }
  1774. VOID UnRegisterHeap(PHEAP pheap)
  1775. {
  1776. if (pheap->pfnHeapMon)
  1777. pheap->pfnHeapMon(pheap, HEAPMON_UNLOAD);
  1778. }
  1779. /*
  1780. - HeapDumpLeaksHeader
  1781. -
  1782. * Purpose:
  1783. *
  1784. *
  1785. * Parameters:
  1786. *
  1787. *
  1788. * Returns:
  1789. *
  1790. */
  1791. VOID HeapDumpLeaksHeader(FILE * hf, PHEAP pheap, BOOL fNoFree)
  1792. {
  1793. char szDate[16];
  1794. char szTime[16];
  1795. GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, "MMM dd yy", szDate, 16);
  1796. GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, "hh':'mm':'ss tt", szTime, 16);
  1797. fprintf(hf, "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
  1798. fprintf(hf, "DATE: %s\n", szDate);
  1799. fprintf(hf, "TIME: %s\n\n", szTime);
  1800. fprintf(hf, "HEAP NAME: %s\n", pheap->szHeapName);
  1801. fprintf(hf, "MAX ALLOC: %ld\n", pheap->ulAllocNum);
  1802. fprintf(hf, "LEAKED NO_FREE HEAP: %s\n", (fNoFree? "YES" : "NO"));
  1803. fprintf(hf, "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n");
  1804. fprintf(hf, "AllocNum, BlkName, Size, Address, Frame1, Frame2, Frame3, Frame4, Frame5, Frame6, Frame7, Frame8, Frame9, Frame10, Frame11, Frame12\n");
  1805. }
  1806. /*
  1807. - HeapDumpLeaksFooter
  1808. -
  1809. * Purpose:
  1810. *
  1811. *
  1812. * Parameters:
  1813. *
  1814. *
  1815. * Returns:
  1816. *
  1817. */
  1818. VOID HeapDumpLeaksFooter(FILE * hf, DWORD cLeaks, DWORD cbLeaked)
  1819. {
  1820. fprintf(hf, "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
  1821. fprintf(hf, "TOTAL NUM OF LEAKS: %ld\n", cLeaks);
  1822. fprintf(hf, "TOTAL BYTES LEAKED: %ld\n", cbLeaked);
  1823. fprintf(hf, "END\n");
  1824. fprintf(hf, "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n\n");
  1825. }
  1826. /*
  1827. - HeapDumpLeakedBlock
  1828. -
  1829. * Purpose:
  1830. * To report individual memory leaks through DebugTrace and the
  1831. * HeapLeakHook breakpoint function.
  1832. */
  1833. VOID HeapDumpLeakedBlock(FILE * hf, PHEAP pheap, PHBLK phblk)
  1834. {
  1835. char rgchSymbols[4096];
  1836. HANDLE hProcess = GetCurrentProcess();
  1837. fprintf(hf, "%ld, %s, %ld, %p",
  1838. phblk->ulAllocNum,
  1839. *phblk->szName ? phblk->szName : "NONAME",
  1840. CbPhblkClient(phblk),
  1841. PhblkToPv(phblk));
  1842. *rgchSymbols = '\0';
  1843. GetStackSymbols(hProcess, rgchSymbols, phblk->rgdwCallers, cFrames);
  1844. if (hf)
  1845. fprintf(hf, "%s\n", rgchSymbols);
  1846. if (fDumpLeaksDebugger)
  1847. {
  1848. char *szSymbol = rgchSymbols;
  1849. char *szSymbolNext = rgchSymbols;
  1850. int iSymbol = 0;
  1851. Trace("Block#%d, %s, %ld, %08lX:\n", phblk->ulAllocNum, *phblk->szName ? phblk->szName : "NONAME",
  1852. CbPhblkClient(phblk), PhblkToPv(phblk));
  1853. while ((szSymbolNext = strchr(szSymbol, ',')) != NULL)
  1854. {
  1855. *szSymbolNext++ = '\0';
  1856. if (*szSymbol != '\0' && strcmp(szSymbol, "0") != 0)
  1857. {
  1858. Trace("\t[%d]: %s\n", iSymbol, szSymbol);
  1859. }
  1860. szSymbol += strlen(szSymbol)+1;
  1861. iSymbol += 1;
  1862. }
  1863. //
  1864. // Dump the last entry in the call stack.
  1865. //
  1866. if (*szSymbol != '\0' && strcmp(szSymbol, "0") != 0)
  1867. {
  1868. Trace("\t[%d]: %s\n", iSymbol, szSymbol);
  1869. }
  1870. }
  1871. }
  1872. /*
  1873. - HeapDumpLeaks
  1874. -
  1875. * Purpose:
  1876. * Gets called at HeapClose time to report any memory leaks against
  1877. * this heap. There are 2 reporting fascilities used by this routine:
  1878. *
  1879. * => Asserts (via TrapSz)
  1880. * => Trace files
  1881. * => Debug trace tags (via DebugTrace)
  1882. *
  1883. * The Debug Trace is the default method if no others are specified
  1884. * or if the others are in-appropriate for the given platform.
  1885. */
  1886. VOID HeapDumpLeaks(PHEAP pheap, BOOL fNoFree)
  1887. {
  1888. PHBLK phblk;
  1889. BOOL fDump = !!(pheap->ulFlags & HEAP_DUMP_LEAKS);
  1890. BOOL fAssert = !!(pheap->ulFlags & HEAP_ASSERT_LEAKS);
  1891. char szLeakLog[MAX_PATH];
  1892. DWORD cLeaks = 0;
  1893. DWORD cbLeaked = 0;
  1894. FILE * hLeakLog = NULL;
  1895. GetLogFilePath(rgchLogPath, ".mem", szLeakLog);
  1896. hLeakLog = fopen(szLeakLog, "a");
  1897. if (!hLeakLog)
  1898. goto ret;
  1899. if (pheap->phblkHead != NULL)
  1900. {
  1901. if (fAssert)
  1902. {
  1903. AssertSz(FALSE, "Memory Leak Detected, dumping leaks");
  1904. }
  1905. if (!fSymInitialize)
  1906. {
  1907. rgsymcacheHashTable = VirtualAlloc(
  1908. NULL,
  1909. NBUCKETS*sizeof(SYMCACHE),
  1910. MEM_COMMIT,
  1911. PAGE_READWRITE);
  1912. if (rgsymcacheHashTable == NULL)
  1913. {
  1914. return;
  1915. }
  1916. SymInitialize(GetCurrentProcess(), NULL, TRUE);
  1917. fSymInitialize = TRUE;
  1918. }
  1919. HeapDumpLeaksHeader(hLeakLog, pheap, fNoFree);
  1920. if (fDump)
  1921. {
  1922. for (phblk = pheap->phblkHead; phblk; phblk = phblk->phblkNext)
  1923. {
  1924. HeapDumpLeakedBlock(hLeakLog, pheap, phblk);
  1925. cLeaks++;
  1926. cbLeaked += phblk->ulSize;
  1927. }
  1928. }
  1929. }
  1930. HeapDumpLeaksFooter(hLeakLog, cLeaks, cbLeaked);
  1931. ret:
  1932. if (hLeakLog)
  1933. fclose(hLeakLog);
  1934. }
  1935. /*
  1936. - HeapValidatePhblk
  1937. -
  1938. * Purpose:
  1939. *
  1940. *
  1941. * Parameters:
  1942. *
  1943. *
  1944. * Returns:
  1945. *
  1946. *
  1947. */
  1948. BOOL HeapValidatePhblk(PHEAP pheap, PHBLK phblk, char ** pszReason)
  1949. {
  1950. if (IsBadWritePtr(phblk, sizeof(HBLK)))
  1951. {
  1952. *pszReason = "Block header cannot be written to";
  1953. goto err;
  1954. }
  1955. if (phblk->pheap != pheap)
  1956. {
  1957. *pszReason = "Block header does not have correct pointer back to heap";
  1958. goto err;
  1959. }
  1960. if (phblk->phblkNext)
  1961. {
  1962. if (IsBadWritePtr(phblk->phblkNext, sizeof(HBLK)))
  1963. {
  1964. *pszReason = "Block header has invalid next link pointer";
  1965. goto err;
  1966. }
  1967. if (phblk->phblkNext->phblkPrev != phblk)
  1968. {
  1969. *pszReason = "Block header points to a next block which doesn't "
  1970. "point back to it";
  1971. goto err;
  1972. }
  1973. }
  1974. if (phblk->phblkPrev)
  1975. {
  1976. if (IsBadWritePtr(phblk->phblkPrev, sizeof(HBLK))) {
  1977. *pszReason = "Block header has invalid prev link pointer";
  1978. goto err;
  1979. }
  1980. if (phblk->phblkPrev->phblkNext != phblk)
  1981. {
  1982. *pszReason = "Block header points to a prev block which doesn't "
  1983. "point back to it";
  1984. goto err;
  1985. }
  1986. }
  1987. else if (pheap->phblkHead != phblk)
  1988. {
  1989. *pszReason = "Block header has a zero prev link but the heap doesn't "
  1990. "believe it is the first block";
  1991. goto err;
  1992. }
  1993. if (phblk->ulAllocNum > pheap->ulAllocNum)
  1994. {
  1995. *pszReason = "Block header has an invalid internal allocation number";
  1996. goto err;
  1997. }
  1998. return TRUE;
  1999. err:
  2000. return FALSE;
  2001. }
  2002. /*
  2003. - HeapDidAlloc
  2004. -
  2005. * Purpose:
  2006. *
  2007. *
  2008. * Parameters:
  2009. *
  2010. *
  2011. * Returns:
  2012. *
  2013. *
  2014. */
  2015. BOOL HeapDidAlloc(PHEAP pheap, LPVOID pv)
  2016. {
  2017. PHBLK phblk;
  2018. char * pszReason;
  2019. BOOL fDidAlloc = FALSE;
  2020. for (phblk = pheap->phblkHead; phblk; phblk = phblk->phblkNext)
  2021. {
  2022. AssertSz(HeapValidatePhblk(pheap, phblk, &pszReason),
  2023. "Invalid block header in ExchMem");
  2024. if (!HeapValidatePhblk(pheap, phblk, &pszReason))
  2025. DebugTrace2("Block header (phblk=%08lX) is invalid\n%s", phblk, pszReason);
  2026. if (PhblkToPv(phblk) == pv)
  2027. {
  2028. fDidAlloc = TRUE;
  2029. break;
  2030. }
  2031. }
  2032. return fDidAlloc;
  2033. }
  2034. /*
  2035. - DumpFailedValidate
  2036. -
  2037. * Purpose:
  2038. *
  2039. *
  2040. * Parameters:
  2041. *
  2042. *
  2043. * Returns:
  2044. *
  2045. */
  2046. VOID DumpFailedValidate(char * szFailed, DWORD_PTR * rgdwStack)
  2047. {
  2048. FILE * hLog = NULL;
  2049. char szValidateLog[MAX_PATH];
  2050. char rgchBuff[2048];
  2051. lstrcpy(rgchBuff, "Stack Trace: ");
  2052. GetStackSymbols(GetCurrentProcess(), rgchBuff, rgdwStack, cFrames);
  2053. // Create validate log file name
  2054. GetLogFilePath(rgchLogPath, ".val", szValidateLog);
  2055. // Open the Log File and write results
  2056. hLog = fopen(szValidateLog, "a");
  2057. if (hLog)
  2058. {
  2059. fprintf(hLog, "%s", szFailed);
  2060. fprintf(hLog, "%s\n\n", rgchBuff);
  2061. fclose(hLog);
  2062. }
  2063. }
  2064. /*
  2065. - HeapValidatePv
  2066. -
  2067. * Purpose:
  2068. *
  2069. *
  2070. * Parameters:
  2071. *
  2072. *
  2073. * Returns:
  2074. *
  2075. *
  2076. */
  2077. BOOL HeapValidatePv(PHEAP pheap, LPVOID pv, char * pszFunc)
  2078. {
  2079. PHBLK phblk;
  2080. char * pszReason;
  2081. char szBuff[1024];
  2082. DWORD_PTR rgdwStack[NSTK];
  2083. LPBYTE pb;
  2084. phblk = PvToPhblk(pheap, pv);
  2085. if (!phblk)
  2086. {
  2087. //
  2088. // Let's see if this block is on the free list.
  2089. //
  2090. if (fTrackFreedMemory && (phblk = PhblkSearchFreeList(pheap, pv)))
  2091. {
  2092. char rgchStackFree[2048];
  2093. char rgchStackAlloc[2048];
  2094. strcpy(szBuff, "Attempt to free already freed memory");
  2095. if (fAssertValid)
  2096. AssertSz(0, szBuff);
  2097. //
  2098. // Dump call stack that corresponds to the earlier free.
  2099. //
  2100. GetStackSymbols(GetCurrentProcess(), rgchStackFree, phblk->rgdwFree, cFrames);
  2101. GetStackSymbols(GetCurrentProcess(), rgchStackAlloc, phblk->rgdwCallers, cFrames);
  2102. Trace("Call stack of freeing routine: \n");
  2103. Trace("%s\n", rgchStackFree);
  2104. Trace("Call stack of allocating routine: \n");
  2105. Trace("%s\n", rgchStackAlloc);
  2106. if (fTrapOnInvalid)
  2107. DebugBreak();
  2108. }
  2109. else
  2110. {
  2111. wsprintf(szBuff, "%s detected a memory block (%08lX) which was either "
  2112. "not allocated in heap '%s' or has already been freed but is not on the free list.\n",
  2113. pszFunc, pv, pheap->szHeapName);
  2114. if (fAssertValid)
  2115. AssertSz(0, szBuff);
  2116. if (fTrapOnInvalid)
  2117. DebugBreak();
  2118. GetCallStack(rgdwStack, cFrames);
  2119. DumpFailedValidate(szBuff, rgdwStack);
  2120. DebugTrace(szBuff);
  2121. }
  2122. return FALSE;
  2123. }
  2124. if (fOverwriteDetect)
  2125. {
  2126. pb = (LPBYTE)PvHeadFromPv(pv);
  2127. if ((pb[0] != chOWFill) || (pb[1] != chOWFill) ||
  2128. (pb[2] != chOWFill) || (pb[3] != chOWFill))
  2129. {
  2130. wsprintf(szBuff, "%s detected a memory block (%08lX) from heap '%s' "
  2131. "which appears to have been under-written.\n",
  2132. pszFunc, pv, pheap->szHeapName);
  2133. if (fAssertValid)
  2134. AssertSz(0, szBuff);
  2135. if (fTrapOnInvalid)
  2136. DebugBreak();
  2137. GetCallStack(rgdwStack, cFrames);
  2138. DumpFailedValidate(szBuff, rgdwStack);
  2139. DebugTrace(szBuff);
  2140. return FALSE;
  2141. }
  2142. pb = (LPBYTE)PvTailFromPv(pv, phblk->ulSize);
  2143. if ((pb[0] != chOWFill) || (pb[1] != chOWFill) ||
  2144. (pb[2] != chOWFill) || (pb[3] != chOWFill))
  2145. {
  2146. wsprintf(szBuff, "%s detected a memory block (%08lX) from heap '%s' "
  2147. "which appears to have been over-written.\n",
  2148. pszFunc, pv, pheap->szHeapName);
  2149. if (fAssertValid)
  2150. AssertSz(0, szBuff);
  2151. if (fTrapOnInvalid)
  2152. DebugBreak();
  2153. GetCallStack(rgdwStack, cFrames);
  2154. DumpFailedValidate(szBuff, rgdwStack);
  2155. DebugTrace(szBuff);
  2156. return FALSE;
  2157. }
  2158. }
  2159. if (!HeapValidatePhblk(pheap, phblk, &pszReason))
  2160. {
  2161. wsprintf(szBuff, "%s detected an invalid memory block (%08lX) in heap '%s'. %s.\n",
  2162. pszFunc, pv, pheap->szHeapName, pszReason);
  2163. if (fAssertValid)
  2164. AssertSz(0, szBuff);
  2165. if (fTrapOnInvalid)
  2166. DebugBreak();
  2167. GetCallStack(rgdwStack, cFrames);
  2168. DumpFailedValidate(szBuff, rgdwStack);
  2169. DebugTrace(szBuff);
  2170. return FALSE;
  2171. }
  2172. return TRUE;
  2173. }
  2174. /*
  2175. - PhblkEnqueue
  2176. -
  2177. * Purpose:
  2178. * To add a newly allocated block to the allocation list hanging
  2179. * off the heap. We do an InsertSorted because the HeapMonitor
  2180. * will need to reference the allocations ordered by their
  2181. * location in the heap. Since the monitor will walk the heap
  2182. * often, it is more efficient to do the sort up front.
  2183. */
  2184. VOID PhblkEnqueue(PHBLK phblk)
  2185. {
  2186. phblk->phblkNext = phblk->pheap->phblkHead;
  2187. if (phblk->phblkNext)
  2188. phblk->phblkNext->phblkPrev = phblk;
  2189. phblk->pheap->phblkHead = phblk;
  2190. // I am going to disable the InsertSorted behavior for now for performance
  2191. // reasons. It is only done this way because of GLHMON which I don't believe
  2192. // to be widely used at this point anyway. I'm not even sure if this is
  2193. // important to GLHMON since it has the ability to sort blocks by other fields.
  2194. /* PHBLK phblkCurr = NULL;
  2195. PHBLK phblkNext = phblk->pheap->phblkHead;
  2196. while (phblkNext)
  2197. {
  2198. if (phblkNext > phblk)
  2199. break;
  2200. phblkCurr = phblkNext;
  2201. phblkNext = phblkCurr->phblkNext;
  2202. }
  2203. if (phblkNext)
  2204. {
  2205. phblk->phblkNext = phblkNext;
  2206. phblk->phblkPrev = phblkCurr;
  2207. phblkNext->phblkPrev = phblk;
  2208. }
  2209. else
  2210. {
  2211. phblk->phblkNext = NULL;
  2212. phblk->phblkPrev = phblkCurr;
  2213. }
  2214. if (phblkCurr)
  2215. phblkCurr->phblkNext = phblk;
  2216. else
  2217. phblk->pheap->phblkHead = phblk;
  2218. */
  2219. }
  2220. /*
  2221. - PhblkDequeue
  2222. -
  2223. * Purpose:
  2224. * To remove a freed block from the list of allocations hanging
  2225. * off the heap.
  2226. */
  2227. VOID PhblkDequeue(PHBLK phblk)
  2228. {
  2229. //
  2230. // We should never be dequeuing an already freed block.
  2231. //
  2232. Assert(phblk->phblkFreeNext == NULL);
  2233. if (phblk->phblkNext)
  2234. phblk->phblkNext->phblkPrev = phblk->phblkPrev;
  2235. if (phblk->phblkPrev)
  2236. phblk->phblkPrev->phblkNext = phblk->phblkNext;
  2237. else
  2238. phblk->pheap->phblkHead = phblk->phblkNext;
  2239. }
  2240. /*
  2241. - HexByteToBin
  2242. -
  2243. * Purpose:
  2244. * Takes a hex string and converts the 2 msd's to a byte, ignoring
  2245. * the remaining digits. This function assumes the string is
  2246. * formatted as: 0xnn, otherwise it simply returns 0x00.
  2247. */
  2248. BYTE HexByteToBin(LPSTR sz)
  2249. {
  2250. int i, n[2], nT;
  2251. if (*sz++ != '0')
  2252. return 0x00;
  2253. nT = *sz++;
  2254. if (nT != 'x' && nT != 'X')
  2255. return 0x00;
  2256. for (i = 0; i < 2; i++)
  2257. {
  2258. nT = *sz++;
  2259. if (nT >= '0' && nT <= '9')
  2260. n[i] = nT - '0';
  2261. else if (nT >= 'A' && nT <= 'F')
  2262. n[i] = nT - 'A' + 10;
  2263. else if (nT >= 'a' && nT <= 'f')
  2264. n[i] = nT - 'a' + 10;
  2265. else
  2266. return (BYTE)0x00;
  2267. }
  2268. n[0] <<= 4;
  2269. return (BYTE)((BYTE)n[0] | (BYTE)n[1]);
  2270. }
  2271. /*
  2272. - Function
  2273. -
  2274. * Purpose:
  2275. *
  2276. *
  2277. * Parameters:
  2278. *
  2279. *
  2280. * Returns:
  2281. *
  2282. */
  2283. void __cdecl HeapSetHeapNameFn(PHEAP pheap, char *pszFormat, ...)
  2284. {
  2285. char sz[512];
  2286. va_list vl;
  2287. if (fDbgEnable)
  2288. {
  2289. va_start(vl, pszFormat);
  2290. wvsprintf(sz, pszFormat, vl);
  2291. va_end(vl);
  2292. lstrcpyn(pheap->szHeapName, sz, sizeof(pheap->szHeapName));
  2293. }
  2294. }
  2295. /*
  2296. - Function
  2297. -
  2298. * Purpose:
  2299. *
  2300. *
  2301. * Parameters:
  2302. *
  2303. *
  2304. * Returns:
  2305. *
  2306. */
  2307. VOID __cdecl HeapSetNameFn(PHEAP pheap, LPVOID pv, char *pszFormat, ...)
  2308. {
  2309. char sz[512];
  2310. PHBLK phblk;
  2311. va_list vl;
  2312. phblk = PvToPhblk(pheap, pv);
  2313. if (phblk)
  2314. {
  2315. va_start(vl, pszFormat);
  2316. wvsprintf(sz, pszFormat, vl);
  2317. va_end(vl);
  2318. lstrcpyn(phblk->szName, sz, sizeof(phblk->szName));
  2319. }
  2320. }
  2321. /*
  2322. - Function
  2323. -
  2324. * Purpose:
  2325. *
  2326. *
  2327. * Parameters:
  2328. *
  2329. *
  2330. * Returns:
  2331. *
  2332. */
  2333. char * HeapGetName(PHEAP pheap, LPVOID pv)
  2334. {
  2335. PHBLK phblk;
  2336. phblk = PvToPhblk(pheap, pv);
  2337. if (phblk)
  2338. return(phblk->szName);
  2339. return("");
  2340. }
  2341. /*
  2342. - Function
  2343. -
  2344. * Purpose:
  2345. *
  2346. *
  2347. * Parameters:
  2348. *
  2349. *
  2350. * Returns:
  2351. *
  2352. */
  2353. BOOL FForceFailure(PHEAP pheap, ULONG cb)
  2354. {
  2355. // First, see if we're past our start of failures point
  2356. if (pheap->ulFailStart && (pheap->ulFailStart <= pheap->ulAllocNum))
  2357. {
  2358. // If so, then are we at an interval where we should return errors?
  2359. if ((pheap->ulFailInterval)
  2360. && ((pheap->ulAllocNum - pheap->ulFailStart)%pheap->ulFailInterval) == 0)
  2361. {
  2362. // return that we should fail here
  2363. return TRUE;
  2364. }
  2365. // Check to see if the alloc size is greater than allowed
  2366. if (pheap->ulFailBufSize && cb >= pheap->ulFailBufSize)
  2367. return TRUE;
  2368. }
  2369. // Otherwise, no error is returned for this alloc
  2370. return FALSE;
  2371. }
  2372. /*
  2373. - PvToPhblk
  2374. -
  2375. * Purpose:
  2376. * Finds the HBLK for this allocation in the heap's active list.
  2377. */
  2378. PHBLK PvToPhblk(PHEAP pheap, LPVOID pv)
  2379. {
  2380. PHBLK phblk;
  2381. EnterCriticalSection(&pheap->cs);
  2382. phblk = pheap->phblkHead;
  2383. while (phblk)
  2384. {
  2385. if (phblk->pv == pv)
  2386. break;
  2387. phblk = phblk->phblkNext;
  2388. }
  2389. LeaveCriticalSection(&pheap->cs);
  2390. return phblk;
  2391. }
  2392. /*
  2393. - IsRunningAsService
  2394. -
  2395. * Purpose:
  2396. * Determine if the process that attached to us is running as a
  2397. * service or not.
  2398. *
  2399. * Parameters:
  2400. * VOID
  2401. *
  2402. * Returns:
  2403. * fService TRUE if a service, FALSE if not
  2404. *
  2405. */
  2406. BOOL IsProcessRunningAsService(VOID)
  2407. {
  2408. HANDLE hProcessToken = NULL;
  2409. DWORD dwGroupLength = 50;
  2410. PTOKEN_GROUPS ptokenGroupInfo = NULL;
  2411. PSID psidInteractive = NULL;
  2412. PSID psidService = NULL;
  2413. SID_IDENTIFIER_AUTHORITY siaNt = SECURITY_NT_AUTHORITY;
  2414. BOOL fService = FALSE;
  2415. DWORD i;
  2416. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken))
  2417. goto ret;
  2418. ptokenGroupInfo = (PTOKEN_GROUPS)LocalAlloc(0, dwGroupLength);
  2419. if (ptokenGroupInfo == NULL)
  2420. goto ret;
  2421. if (!GetTokenInformation(hProcessToken, TokenGroups, ptokenGroupInfo,
  2422. dwGroupLength, &dwGroupLength))
  2423. {
  2424. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  2425. goto ret;
  2426. LocalFree(ptokenGroupInfo);
  2427. ptokenGroupInfo = NULL;
  2428. ptokenGroupInfo = (PTOKEN_GROUPS)LocalAlloc(0, dwGroupLength);
  2429. if (ptokenGroupInfo == NULL)
  2430. goto ret;
  2431. if (!GetTokenInformation(hProcessToken, TokenGroups, ptokenGroupInfo,
  2432. dwGroupLength, &dwGroupLength))
  2433. {
  2434. goto ret;
  2435. }
  2436. }
  2437. // We now know the groups associated with this token. We want to look
  2438. // to see if the interactive group is active in the token, and if so,
  2439. // we know that this is an interactive process.
  2440. //
  2441. // We also look for the "service" SID, and if it's present, we know
  2442. // we're a service.
  2443. //
  2444. // The service SID will be present iff the service is running in a
  2445. // user account (and was invoked by the service controller).
  2446. if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_INTERACTIVE_RID, 0, 0,
  2447. 0, 0, 0, 0, 0, &psidInteractive))
  2448. {
  2449. goto ret;
  2450. }
  2451. if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_SERVICE_RID, 0, 0, 0,
  2452. 0, 0, 0, 0, &psidService))
  2453. {
  2454. goto ret;
  2455. }
  2456. for (i = 0; i < ptokenGroupInfo->GroupCount ; i += 1)
  2457. {
  2458. PSID psid = ptokenGroupInfo->Groups[i].Sid;
  2459. // Check to see if the group we're looking at is one of
  2460. // the 2 groups we're interested in.
  2461. if (EqualSid(psid, psidInteractive))
  2462. {
  2463. // This process has the Interactive SID in its token.
  2464. // This means that the process is running as an EXE.
  2465. goto ret;
  2466. }
  2467. else if (EqualSid(psid, psidService))
  2468. {
  2469. // This process has the Service SID in its token. This means that
  2470. // the process is running as a service running in a user account.
  2471. fService = TRUE;
  2472. goto ret;
  2473. }
  2474. }
  2475. // Neither Interactive or Service was present in the current
  2476. // users token. This implies that the process is running as
  2477. // a service, most likely running as LocalSystem.
  2478. fService = TRUE;
  2479. ret:
  2480. if (psidInteractive)
  2481. FreeSid(psidInteractive);
  2482. if (psidService)
  2483. FreeSid(psidService);
  2484. if (ptokenGroupInfo)
  2485. LocalFree(ptokenGroupInfo);
  2486. if (hProcessToken)
  2487. CloseHandle(hProcessToken);
  2488. return fService;
  2489. }
  2490. /*
  2491. - DebugTraceFn
  2492. -
  2493. * Purpose:
  2494. *
  2495. *
  2496. * Parameters:
  2497. *
  2498. *
  2499. * Returns:
  2500. *
  2501. */
  2502. void __cdecl DebugTraceFn(char *pszFormat, ...)
  2503. {
  2504. char sz[4096];
  2505. va_list vl;
  2506. va_start(vl, pszFormat);
  2507. wvsprintfA(sz, pszFormat, vl);
  2508. va_end(vl);
  2509. OutputDebugStringA(sz);
  2510. OutputDebugStringA("\r");
  2511. }
  2512. /*
  2513. - AssertFn
  2514. -
  2515. * Purpose:
  2516. *
  2517. *
  2518. * Parameters:
  2519. *
  2520. *
  2521. * Returns:
  2522. *
  2523. */
  2524. void AssertFn(char * szFile, int nLine, char * szMsg)
  2525. {
  2526. int nRet;
  2527. char szInfo[1024];
  2528. wsprintf(szInfo, "File %.64s @ line %d%s%s",
  2529. szFile,
  2530. nLine,
  2531. (szMsg) ? (": ") : (""),
  2532. (szMsg) ? (szMsg) : (""));
  2533. // OK to continue, CANCEL to break.
  2534. nRet = MessageBox(NULL, szInfo, "ExchMem Assert", MB_OKCANCEL | MB_ICONSTOP | MB_SERVICE_NOTIFICATION | MB_TOPMOST);
  2535. if (nRet == IDCANCEL)
  2536. DebugBreak();
  2537. }
  2538. void
  2539. ExchmemGetCallStack(DWORD_PTR *rgdwCaller, DWORD cFind)
  2540. {
  2541. if (fSymbolLookup)
  2542. {
  2543. GetCallStack(rgdwCaller, cFind);
  2544. }
  2545. else
  2546. {
  2547. ZeroMemory(rgdwCaller, cFind*sizeof(DWORD));
  2548. }
  2549. }
  2550. BOOL FTrackMem()
  2551. {
  2552. if (InterlockedCompareExchange(&fChangeTrackState,FALSE,TRUE))
  2553. {
  2554. fTrackMem = !fTrackMem;
  2555. if (fTrackMem)
  2556. StartTrace(FALSE);
  2557. else
  2558. StopTrace();
  2559. }
  2560. return fTrackMem;
  2561. }
  2562. void
  2563. StartTrace(BOOL fFresh)
  2564. {
  2565. char szTrackLog[MAX_PATH];
  2566. GetLogFilePath(rgchLogPath, ".trk", szTrackLog);
  2567. InitializeCriticalSection(&csTrackLog);
  2568. // Open the Log File
  2569. hTrackLog = fopen(szTrackLog, fFresh ? "wt" : "at");
  2570. if (!hTrackLog)
  2571. {
  2572. DeleteCriticalSection(&csTrackLog);
  2573. fTrackMem = FALSE;
  2574. }
  2575. }
  2576. void
  2577. StopTrace()
  2578. {
  2579. DeleteCriticalSection(&csTrackLog);
  2580. if (hTrackLog)
  2581. {
  2582. fclose(hTrackLog);
  2583. hTrackLog = NULL;
  2584. }
  2585. fTrackMem = FALSE;
  2586. }
  2587. //-------------------------------------------------------------------------------------
  2588. // Description:
  2589. // Copies szAppend to szBuf and updates szBuf to point to the terminating NULL of
  2590. // of the copied bytes. cbMaxBuf is max chars available in szBuf. cbAppend is
  2591. // strlen(szAppend). If cbAppend > cbMaxBuf, as many characters as possible are
  2592. // copied to szBuf (including terminating NULL).
  2593. //-------------------------------------------------------------------------------------
  2594. #define ExchmemSafeAppend(szBuf, cbMaxBuf, szAppend, cbAppend) { \
  2595. int iWritten; \
  2596. \
  2597. if(NULL != lstrcpyn(szBuf, szAppend, cbMaxBuf)) { \
  2598. iWritten = ((int)cbMaxBuf < (int)cbAppend) ? cbMaxBuf : cbAppend; \
  2599. szBuf += iWritten; \
  2600. cbMaxBuf -= iWritten; \
  2601. } \
  2602. }
  2603. void
  2604. ExchmemFormatSymbol(HANDLE hProcess, DWORD_PTR dwAddress, char rgchSymbol[], DWORD cbSymbol)
  2605. {
  2606. CHAR rgchModuleName[16];
  2607. BOOL fSym;
  2608. IMAGEHLP_MODULE mi = {0};
  2609. PIMAGEHLP_SYMBOL psym = NULL;
  2610. LPSTR pszSymName = NULL;
  2611. CHAR rgchLine[256];
  2612. LPSTR pszT = NULL;
  2613. DWORD_PTR dwOffset = 0;
  2614. int cbAppend = 0;
  2615. PCHAR pchSymbol = rgchSymbol;
  2616. mi.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
  2617. pszSymName = pfMalloc(256);
  2618. if (!pszSymName)
  2619. goto ret;
  2620. psym = pfMalloc(sizeof(IMAGEHLP_SYMBOL) + 256);
  2621. if (!psym)
  2622. goto ret;
  2623. ZeroMemory(psym, sizeof(IMAGEHLP_SYMBOL) + 256);
  2624. psym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  2625. psym->MaxNameLength = 256;
  2626. rgchSymbol[0] = '\0';
  2627. if (SymGetModuleInfo(hProcess, dwAddress, &mi))
  2628. {
  2629. lstrcpy(rgchModuleName, mi.ModuleName);
  2630. RemoveExtension(rgchModuleName);
  2631. cbAppend = wsprintf(rgchLine, "(%s)", rgchModuleName);
  2632. ExchmemSafeAppend(pchSymbol, cbSymbol, rgchLine, cbAppend);
  2633. }
  2634. else
  2635. ExchmemSafeAppend(pchSymbol, cbSymbol, "none", sizeof("none") - 1);
  2636. if (fSymbolLookup)
  2637. {
  2638. //
  2639. // Make sure we always get the address of the symbol, since the symbol lookup isn't accurate for
  2640. // all modules.
  2641. //
  2642. cbAppend = wsprintf(rgchLine, "(0x%p):", dwAddress);
  2643. ExchmemSafeAppend(pchSymbol, cbSymbol, rgchLine, cbAppend);
  2644. pszT = PszGetSymbolFromCache(dwAddress, &dwOffset);
  2645. if (!pszT)
  2646. {
  2647. fSym = SymGetSymFromAddr(hProcess,
  2648. dwAddress,
  2649. &dwOffset,
  2650. psym);
  2651. if (fSym)
  2652. {
  2653. if (!SymUnDName(psym, pszSymName, 248))
  2654. lstrcpyn(pszSymName, &(psym->Name[1]), 248);
  2655. AddSymbolToCache(dwAddress, dwOffset, pszSymName);
  2656. pszT = pszSymName;
  2657. }
  2658. }
  2659. if (pszT)
  2660. {
  2661. ExchmemSafeAppend(pchSymbol, cbSymbol, pszT, lstrlen(pszT));
  2662. cbAppend = wsprintf(rgchLine, "+0x%x", dwOffset);
  2663. ExchmemSafeAppend(pchSymbol, cbSymbol, rgchLine, cbAppend);
  2664. }
  2665. else
  2666. {
  2667. cbAppend = wsprintf(rgchLine, "(0x%08x)", dwAddress);
  2668. ExchmemSafeAppend(pchSymbol, cbSymbol, rgchLine, cbAppend);
  2669. }
  2670. }
  2671. else
  2672. {
  2673. cbAppend = wsprintf(rgchLine, "(0x%08x)", dwAddress);
  2674. ExchmemSafeAppend(pchSymbol, cbSymbol, rgchLine, cbAppend);
  2675. }
  2676. ret:
  2677. if (psym)
  2678. pfFree(psym);
  2679. if (pszSymName)
  2680. pfFree(pszSymName);
  2681. }
  2682. /*
  2683. - GetCallStack
  2684. -
  2685. * Purpose:
  2686. * Uses the imagehlp APIs to get the call stack.
  2687. *
  2688. * Parameters:
  2689. * pdwCaller An array of return addresses
  2690. * cFind Count of stack frames to get
  2691. *
  2692. * Returns:
  2693. * VOID
  2694. *
  2695. */
  2696. VOID GetCallStack(DWORD_PTR *rgdwCaller, DWORD cFind)
  2697. {
  2698. BOOL fMore;
  2699. STACKFRAME stkfrm = {0};
  2700. CONTEXT ctxt;
  2701. HANDLE hThread;
  2702. HANDLE hProcess;
  2703. if (!cFind)
  2704. return;
  2705. hThread = GetCurrentThread();
  2706. hProcess = GetCurrentProcess();
  2707. ZeroMemory(&ctxt, sizeof(CONTEXT));
  2708. ZeroMemory(rgdwCaller, cFind * sizeof(DWORD));
  2709. ctxt.ContextFlags = CONTEXT_FULL;
  2710. if (!GetThreadContext(hThread, &ctxt))
  2711. {
  2712. stkfrm.AddrPC.Offset = 0;
  2713. }
  2714. else
  2715. {
  2716. #if defined(_M_IX86)
  2717. _asm
  2718. {
  2719. mov stkfrm.AddrStack.Offset, esp
  2720. mov stkfrm.AddrFrame.Offset, ebp
  2721. mov stkfrm.AddrPC.Offset, offset DummyLabel
  2722. DummyLabel:
  2723. }
  2724. #elif defined(_M_MRX000)
  2725. stkfrm.AddrPC.Offset = ctxt.Fir;
  2726. stkfrm.AddrStack.Offset = ctxt.IntSp;
  2727. stkfrm.AddrFrame.Offset = ctxt.IntSp;
  2728. #elif defined(_M_ALPHA)
  2729. stkfrm.AddrPC.Offset = (ULONG_PTR)ctxt.Fir;
  2730. stkfrm.AddrStack.Offset = (ULONG_PTR)ctxt.IntSp;
  2731. stkfrm.AddrFrame.Offset = (ULONG_PTR)ctxt.IntSp;
  2732. #elif defined(_M_PPC)
  2733. stkfrm.AddrPC.Offset = ctxt.Iar;
  2734. stkfrm.AddrStack.Offset = ctxt.Gpr1;
  2735. stkfrm.AddrFrame.Offset = ctxt.Gpr1;
  2736. #else
  2737. stkfrm.AddrPC.Offset = 0;
  2738. #endif
  2739. }
  2740. stkfrm.AddrPC.Mode = AddrModeFlat;
  2741. stkfrm.AddrStack.Mode = AddrModeFlat;
  2742. stkfrm.AddrFrame.Mode = AddrModeFlat;
  2743. // Eat the first one
  2744. fMore = StackWalk(
  2745. #ifdef _M_IX86
  2746. IMAGE_FILE_MACHINE_I386,
  2747. #elif defined(_M_MRX000)
  2748. IMAGE_FILE_MACHINE_R4000,
  2749. #elif defined(_M_ALPHA)
  2750. #if !defined(_M_AXP64)
  2751. IMAGE_FILE_MACHINE_ALPHA,
  2752. #else
  2753. IMAGE_FILE_MACHINE_ALPHA64,
  2754. #endif
  2755. #elif defined(_M_PPC)
  2756. IMAGE_FILE_MACHINE_POWERPC,
  2757. #else
  2758. IMAGE_FILE_MACHINE_UNKNOWN,
  2759. #endif
  2760. hProcess,
  2761. hThread,
  2762. &stkfrm,
  2763. &ctxt,
  2764. (PREAD_PROCESS_MEMORY_ROUTINE)ReadProcessMemory,
  2765. SymFunctionTableAccess,
  2766. SymGetModuleBase,
  2767. NULL);
  2768. while (fMore && (cFind > 0))
  2769. {
  2770. fMore = StackWalk(
  2771. #ifdef _M_IX86
  2772. IMAGE_FILE_MACHINE_I386,
  2773. #elif defined(_M_MRX000)
  2774. IMAGE_FILE_MACHINE_R4000,
  2775. #elif defined(_M_ALPHA)
  2776. IMAGE_FILE_MACHINE_ALPHA,
  2777. #elif defined(_M_AXP64)
  2778. IMAGE_FILE_MACHINE_ALPHA64,
  2779. #elif defined(_M_PPC)
  2780. IMAGE_FILE_MACHINE_POWERPC,
  2781. #else
  2782. IMAGE_FILE_MACHINE_UNKNOWN,
  2783. #endif
  2784. hProcess,
  2785. hThread,
  2786. &stkfrm,
  2787. &ctxt,
  2788. (PREAD_PROCESS_MEMORY_ROUTINE)ReadProcessMemory,
  2789. SymFunctionTableAccess,
  2790. SymGetModuleBase,
  2791. NULL);
  2792. if (!fMore)
  2793. break;
  2794. *rgdwCaller++ = stkfrm.AddrPC.Offset;
  2795. cFind -= 1;
  2796. }
  2797. }
  2798. /*
  2799. - RemoveExtension
  2800. -
  2801. * Purpose:
  2802. * Strips the file extension from a file path.
  2803. *
  2804. * Parameters:
  2805. * psz File path to strip extension from
  2806. *
  2807. * Returns:
  2808. * void
  2809. */
  2810. VOID RemoveExtension(LPSTR psz)
  2811. {
  2812. LPSTR szLast = NULL;
  2813. while (*psz)
  2814. {
  2815. if (*psz == '.')
  2816. {
  2817. szLast = psz;
  2818. }
  2819. psz++;
  2820. }
  2821. if (szLast)
  2822. {
  2823. *szLast = '\0';
  2824. }
  2825. }
  2826. /*
  2827. - GetLogFilePath
  2828. -
  2829. * Purpose:
  2830. * Build a log file path from a supplied path, the current
  2831. * executables name, and a supplied file extension.
  2832. *
  2833. * Parameters:
  2834. * szPath [in] Path to new log file
  2835. * szExt [in] New log file extension
  2836. * szFilePath [out] Newly constructed log file path
  2837. *
  2838. * Returns:
  2839. * void
  2840. */
  2841. VOID GetLogFilePath(LPSTR szPath, LPSTR szExt, LPSTR szFilePath)
  2842. {
  2843. lstrcpy(szFilePath, szPath);
  2844. lstrcat(szFilePath, rgchExeName);
  2845. lstrcat(szFilePath, szExt);
  2846. }
  2847. /*
  2848. - PszGetSymbolFromCache
  2849. -
  2850. * Purpose:
  2851. *
  2852. *
  2853. * Parameters:
  2854. *
  2855. *
  2856. * Returns:
  2857. *
  2858. */
  2859. CHAR * PszGetSymbolFromCache(DWORD_PTR dwAddress, DWORD_PTR * pdwOffset)
  2860. {
  2861. ULONG ulBucket = UlHash(dwAddress);
  2862. if (rgsymcacheHashTable[ulBucket].dwAddress == dwAddress)
  2863. {
  2864. *pdwOffset = rgsymcacheHashTable[ulBucket].dwOffset;
  2865. return rgsymcacheHashTable[ulBucket].rgchSymbol;
  2866. }
  2867. return NULL;
  2868. }
  2869. /*
  2870. - AddSymbolToCache
  2871. -
  2872. * Purpose:
  2873. *
  2874. *
  2875. * Parameters:
  2876. *
  2877. *
  2878. * Returns:
  2879. *
  2880. */
  2881. VOID AddSymbolToCache(DWORD_PTR dwAddress, DWORD_PTR dwOffset, CHAR * pszSymbol)
  2882. {
  2883. ULONG ulBucket = UlHash(dwAddress);
  2884. rgsymcacheHashTable[ulBucket].dwAddress = dwAddress;
  2885. rgsymcacheHashTable[ulBucket].dwOffset = dwOffset;
  2886. lstrcpy(rgsymcacheHashTable[ulBucket].rgchSymbol, pszSymbol);
  2887. }
  2888. /*
  2889. - GetStackSymbols
  2890. -
  2891. * Purpose:
  2892. *
  2893. *
  2894. * Parameters:
  2895. *
  2896. *
  2897. * Returns:
  2898. *
  2899. *
  2900. */
  2901. VOID
  2902. GetStackSymbols(
  2903. HANDLE hProcess,
  2904. CHAR * rgchBuff,
  2905. DWORD_PTR * rgdwStack,
  2906. DWORD cFrames)
  2907. {
  2908. DWORD i;
  2909. DWORD_PTR dwAddress;
  2910. LPSTR pszSymName = NULL;
  2911. pszSymName = pfMalloc(256);
  2912. if (!pszSymName)
  2913. goto ret;
  2914. for (i = 0; i < cFrames; i++)
  2915. {
  2916. if ((dwAddress = rgdwStack[i]) != 0)
  2917. {
  2918. ExchmemFormatSymbol(hProcess, dwAddress, pszSymName, 256);
  2919. lstrcat(rgchBuff, ",");
  2920. lstrcat(rgchBuff, pszSymName);
  2921. }
  2922. else
  2923. lstrcat(rgchBuff, ",0");
  2924. }
  2925. ret:
  2926. if (pszSymName)
  2927. pfFree(pszSymName);
  2928. return;
  2929. }
  2930. /*
  2931. - LogCurrentAPI
  2932. -
  2933. * Purpose:
  2934. *
  2935. *
  2936. * Parameters:
  2937. *
  2938. *
  2939. * Returns:
  2940. *
  2941. *
  2942. */
  2943. VOID LogCurrentAPI(
  2944. WORD wApi,
  2945. DWORD_PTR *rgdwCallStack,
  2946. DWORD cFrames,
  2947. DWORD_PTR *rgdwArgs,
  2948. DWORD cArgs)
  2949. {
  2950. CHAR rgchT[64];
  2951. CHAR rgchKeys[8] = "CDARF";
  2952. CHAR rgchBuff[8192];
  2953. DWORD cbWritten;
  2954. if (dwTrackMemInMem)
  2955. {
  2956. long lCurr;
  2957. // Instead of writing out to a file, just maintain the data in a circular memory list.
  2958. // The overflow check is not thread safe, but if we lose an entry or two after two billion
  2959. // memory functions, oh well.
  2960. if (dwmemtrace == 0xefffffff)
  2961. {
  2962. dwmemtrace = 1;
  2963. lCurr = 0;
  2964. }
  2965. else
  2966. lCurr = (InterlockedIncrement((LONG *)&dwmemtrace) - 1) % dwTrackMemInMem;
  2967. memset(&rgmemtrace[lCurr],0,sizeof(MEMTRACE));
  2968. rgmemtrace[lCurr].wApi = wApi;
  2969. memcpy(rgmemtrace[lCurr].rgdwCallStack,rgdwCallStack,cFrames*sizeof(DWORD_PTR));
  2970. memcpy(rgmemtrace[lCurr].rgdwArgs,rgdwArgs,cArgs*sizeof(DWORD_PTR));
  2971. rgmemtrace[lCurr].dwTickCount = GetTickCount();
  2972. rgmemtrace[lCurr].dwThreadId = GetCurrentThreadId();
  2973. return;
  2974. }
  2975. sprintf(rgchBuff, "%c,%lu,%lu", rgchKeys[wApi], GetTickCount(), GetCurrentThreadId());
  2976. if (cFrames)
  2977. GetStackSymbols(GetCurrentProcess(), rgchBuff, rgdwCallStack, cFrames);
  2978. switch (wApi)
  2979. {
  2980. case API_HEAP_CREATE:
  2981. sprintf(rgchT, ",%ld", rgdwArgs[0]); // cbInitSize
  2982. lstrcat(rgchBuff, rgchT);
  2983. sprintf(rgchT, ",%ld", rgdwArgs[1]); // cbMaxSize
  2984. lstrcat(rgchBuff, rgchT);
  2985. sprintf(rgchT, ",0x%08X\n", rgdwArgs[2]); // hHeap
  2986. lstrcat(rgchBuff, rgchT);
  2987. break;
  2988. case API_HEAP_DESTROY:
  2989. sprintf(rgchT, ",0x%08X\n", rgdwArgs[0]); // hHeap
  2990. lstrcat(rgchBuff, rgchT);
  2991. break;
  2992. case API_HEAP_FREE:
  2993. sprintf(rgchT, ",0x%08X", rgdwArgs[0]); // hHeap
  2994. lstrcat(rgchBuff, rgchT);
  2995. sprintf(rgchT, ",0x%08X", rgdwArgs[1]); // pvFree
  2996. lstrcat(rgchBuff, rgchT);
  2997. sprintf(rgchT, ",%ld\n", rgdwArgs[2]); // cbFree
  2998. lstrcat(rgchBuff, rgchT);
  2999. break;
  3000. case API_HEAP_ALLOC:
  3001. sprintf(rgchT, ",0x%08X", rgdwArgs[0]); // hHeap
  3002. lstrcat(rgchBuff, rgchT);
  3003. sprintf(rgchT, ",%ld", rgdwArgs[1]); // cbAlloc
  3004. lstrcat(rgchBuff, rgchT);
  3005. sprintf(rgchT, ",0x%08X\n", rgdwArgs[2]); // pvAlloc
  3006. lstrcat(rgchBuff, rgchT);
  3007. break;
  3008. case API_HEAP_REALLOC:
  3009. sprintf(rgchT, ",0x%08X", rgdwArgs[0]); // hHeap
  3010. lstrcat(rgchBuff, rgchT);
  3011. sprintf(rgchT, ",%ld", rgdwArgs[1]); // cbOld
  3012. lstrcat(rgchBuff, rgchT);
  3013. sprintf(rgchT, ",0x%08X", rgdwArgs[2]); // pvOld
  3014. lstrcat(rgchBuff, rgchT);
  3015. sprintf(rgchT, ",%ld", rgdwArgs[3]); // cbNew
  3016. lstrcat(rgchBuff, rgchT);
  3017. sprintf(rgchT, ",0x%08X\n", rgdwArgs[4]); // pvNew
  3018. lstrcat(rgchBuff, rgchT);
  3019. break;
  3020. }
  3021. EnterCriticalSection(&csTrackLog);
  3022. WriteFile((HANDLE)_get_osfhandle(_fileno(hTrackLog)), rgchBuff, strlen(rgchBuff), &cbWritten, NULL);
  3023. LeaveCriticalSection(&csTrackLog);
  3024. }
  3025. //-----------------------------------------------------------------------------
  3026. // Virtual Memory Support
  3027. //-----------------------------------------------------------------------------
  3028. #define PAGE_SIZE 4096
  3029. #define PvToVMBase(pv) ((LPVOID)((ULONG_PTR)pv & ~0xFFFF))
  3030. /*
  3031. - Function
  3032. -
  3033. * Purpose:
  3034. *
  3035. *
  3036. * Parameters:
  3037. *
  3038. *
  3039. * Returns:
  3040. *
  3041. */
  3042. BOOL
  3043. VMValidatePvEx(
  3044. LPVOID pv,
  3045. ULONG cbCluster)
  3046. {
  3047. LPVOID pvBase;
  3048. LPBYTE pb;
  3049. pvBase = PvToVMBase(pv);
  3050. pb = (BYTE *)pvBase + sizeof(ULONG);
  3051. while (pb < (BYTE *)pv)
  3052. {
  3053. if (*pb++ != 0xAD)
  3054. {
  3055. char szBuff[1024];
  3056. wsprintf(szBuff, "VMValidatePvEx(pv=%08lX): Block leader has been overwritten", pv);
  3057. AssertSz(0, szBuff);
  3058. return FALSE;
  3059. }
  3060. }
  3061. if (cbCluster != 1)
  3062. {
  3063. ULONG cb = *((ULONG *)pvBase);
  3064. ULONG cbPad = 0;
  3065. if (cb % cbCluster)
  3066. cbPad = (cbCluster - (cb % cbCluster));
  3067. if (cbPad)
  3068. {
  3069. BYTE *pbMac;
  3070. pb = (BYTE *)pv + cb;
  3071. pbMac = pb + cbPad;
  3072. while (pb < pbMac)
  3073. {
  3074. if (*pb++ != 0xBC)
  3075. {
  3076. char szBuff[1024];
  3077. wsprintf(szBuff, "VMValidatePvEx(pv=%08lX): Block trailer has been overwritten", pv);
  3078. AssertSz(0, szBuff);
  3079. return FALSE;
  3080. }
  3081. }
  3082. }
  3083. }
  3084. return TRUE;
  3085. }
  3086. /*
  3087. - Function
  3088. -
  3089. * Purpose:
  3090. *
  3091. *
  3092. * Parameters:
  3093. *
  3094. *
  3095. * Returns:
  3096. *
  3097. */
  3098. LPVOID
  3099. WINAPI
  3100. VMAllocEx(
  3101. ULONG cb,
  3102. ULONG cbCluster)
  3103. {
  3104. ULONG cbAlloc;
  3105. LPVOID pvR;
  3106. LPVOID pvC;
  3107. ULONG cbPad = 0;
  3108. // a cluster size of 0 means don't use the virtual allocator.
  3109. AssertSz(cbCluster != 0, "Cluster size is zero.");
  3110. if (cb > 0x400000)
  3111. return NULL;
  3112. if (cb % cbCluster)
  3113. cbPad = (cbCluster - (cb % cbCluster));
  3114. cbAlloc = sizeof(ULONG) + cb + cbPad + PAGE_SIZE - 1;
  3115. cbAlloc -= cbAlloc % PAGE_SIZE;
  3116. cbAlloc += PAGE_SIZE;
  3117. pvR = VirtualAlloc(0, cbAlloc, MEM_RESERVE, PAGE_NOACCESS);
  3118. if (pvR == 0)
  3119. return NULL;
  3120. pvC = VirtualAlloc(pvR, cbAlloc - PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
  3121. if (pvC != pvR)
  3122. {
  3123. VirtualFree(pvR, 0, MEM_RELEASE);
  3124. return NULL;
  3125. }
  3126. *(ULONG *)pvC = cb;
  3127. memset((BYTE *)pvC + sizeof(ULONG), 0xAD,
  3128. (UINT) cbAlloc - cb - cbPad - sizeof(ULONG) - PAGE_SIZE);
  3129. if (cbPad)
  3130. memset((BYTE *)pvC + cbAlloc - PAGE_SIZE - cbPad, 0xBC,
  3131. (UINT) cbPad);
  3132. return ((BYTE *)pvC + (cbAlloc - cb - cbPad - PAGE_SIZE));
  3133. }
  3134. /*
  3135. - Function
  3136. -
  3137. * Purpose:
  3138. *
  3139. *
  3140. * Parameters:
  3141. *
  3142. *
  3143. * Returns:
  3144. *
  3145. */
  3146. VOID
  3147. WINAPI
  3148. VMFreeEx(
  3149. LPVOID pv,
  3150. ULONG cbCluster)
  3151. {
  3152. VMValidatePvEx(pv, cbCluster);
  3153. if (!VirtualFree(PvToVMBase(pv), 0, MEM_RELEASE))
  3154. {
  3155. char szBuff[1024];
  3156. wsprintf(szBuff, "VMFreeEx(pv=%08lX): VirtualFree failed (%08lX)",
  3157. pv, GetLastError());
  3158. AssertSz(0, szBuff);
  3159. }
  3160. }
  3161. /*
  3162. - Function
  3163. -
  3164. * Purpose:
  3165. *
  3166. *
  3167. * Parameters:
  3168. *
  3169. *
  3170. * Returns:
  3171. *
  3172. */
  3173. LPVOID
  3174. WINAPI
  3175. VMReallocEx(
  3176. LPVOID pv,
  3177. ULONG cb,
  3178. ULONG cbCluster)
  3179. {
  3180. LPVOID* pvNew = 0;
  3181. ULONG cbCopy;
  3182. VMValidatePvEx(pv, cbCluster);
  3183. cbCopy = *(ULONG *)PvToVMBase(pv);
  3184. if (cbCopy > cb)
  3185. cbCopy = cb;
  3186. pvNew = VMAllocEx(cb, cbCluster);
  3187. if (pvNew)
  3188. {
  3189. memcpy(pvNew, pv, cbCopy);
  3190. VMFreeEx(pv, cbCluster);
  3191. }
  3192. return pvNew;
  3193. }
  3194. /*
  3195. - Function
  3196. -
  3197. * Purpose:
  3198. *
  3199. *
  3200. * Parameters:
  3201. *
  3202. *
  3203. * Returns:
  3204. *
  3205. */
  3206. ULONG
  3207. WINAPI
  3208. VMGetSizeEx(
  3209. LPVOID pv,
  3210. ULONG cbCluster)
  3211. {
  3212. return (*(ULONG *)PvToVMBase(pv));
  3213. }
  3214. #ifdef DEBUG
  3215. BOOL
  3216. __stdcall
  3217. FReloadSymbolsCallback(PSTR szModuleName, ULONG_PTR ulBaseOfDLL, ULONG cbSizeOfDLL, void *pvContext)
  3218. {
  3219. if (SymGetModuleBase(GetCurrentProcess(), ulBaseOfDLL) == 0)
  3220. {
  3221. if (!SymLoadModule(GetCurrentProcess(),
  3222. NULL,
  3223. szModuleName,
  3224. NULL,
  3225. ulBaseOfDLL,
  3226. cbSizeOfDLL))
  3227. {
  3228. Trace("Error loading module %s: %d", szModuleName, GetLastError());
  3229. return FALSE;
  3230. }
  3231. }
  3232. return TRUE;
  3233. }
  3234. DWORD
  3235. WINAPI
  3236. ExchmemReloadSymbols(void)
  3237. {
  3238. if (!EnumerateLoadedModules(GetCurrentProcess(), FReloadSymbolsCallback, NULL))
  3239. {
  3240. DWORD ec = GetLastError();
  3241. Trace("SymEnumerateModules failed: %d", ec);
  3242. return ec;
  3243. }
  3244. return 0;
  3245. }
  3246. #endif
  3247. #else // !DEBUG
  3248. void
  3249. ExchmemGetCallStack(DWORD_PTR *rgdwCaller, DWORD cFind)
  3250. {
  3251. //
  3252. // Fill the stack with 0s on a retail EXCHMEM.
  3253. //
  3254. ZeroMemory(rgdwCaller, cFind*sizeof(DWORD));
  3255. }
  3256. void
  3257. ExchmemFormatSymbol(HANDLE hProcess, DWORD_PTR dwCaller, char rgchSymbol[], DWORD cbSymbol)
  3258. {
  3259. //
  3260. // Fill the stack with 0s on a retail EXCHMEM.
  3261. //
  3262. strncpy(rgchSymbol, "Unknown", cbSymbol);
  3263. }
  3264. DWORD
  3265. ExchmemReloadSymbols(void)
  3266. {
  3267. return 0;
  3268. }
  3269. #endif // DEBUG