Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1044 lines
23 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. debug.c
  5. Abstract:
  6. Debug helpers and memory allocation wrappers
  7. Author:
  8. Jim Schmidt (jimschm) 13-Aug-1996
  9. Revision History:
  10. Marc R. Whitten (marcw) 27-May-1997
  11. Added DEBUGLOGTIME() functions and support for the /#U:DOLOG cmd line option.
  12. Ovidiu Temereanca (ovidiut) 06-Nov-1998
  13. Took out log related functions and put them in log.c file
  14. --*/
  15. #include "pch.h"
  16. #include "migutilp.h"
  17. //
  18. // NOTE: No code should appear outside the #ifdef DEBUG
  19. //
  20. #ifdef DEBUG
  21. #pragma message("DEBUG macros enabled")
  22. #define PCVOID LPCVOID
  23. typedef DWORD ALLOCATION_ITEM_OFFSET;
  24. typedef struct _tagTRACKBUCKETITEM {
  25. struct _tagTRACKBUCKETITEM *Next;
  26. struct _tagTRACKBUCKETITEM *Prev;
  27. ALLOCTYPE Type;
  28. PVOID Ptr;
  29. ALLOCATION_ITEM_OFFSET ItemOffset;
  30. } TRACKBUCKETITEM, *PTRACKBUCKETITEM;
  31. #define TRACK_BUCKETS 1501
  32. PTRACKBUCKETITEM g_TrackBuckets[TRACK_BUCKETS];
  33. #define BUCKET_ITEMS_PER_POOL 8192
  34. typedef struct _tagBUCKETPOOL {
  35. UINT Count;
  36. TRACKBUCKETITEM Items[BUCKET_ITEMS_PER_POOL];
  37. } TRACKBUCKETPOOL, *PTRACKBUCKETPOOL;
  38. PTRACKBUCKETITEM g_TrackPoolDelHead;
  39. PTRACKBUCKETPOOL g_TrackPool;
  40. typedef struct _tagTRACKSTRUCT {
  41. DWORD Signature;
  42. PCSTR File;
  43. DWORD Line;
  44. DWORD Size;
  45. PSTR Comment;
  46. struct _tagTRACKSTRUCT *PrevAlloc;
  47. struct _tagTRACKSTRUCT *NextAlloc;
  48. } TRACKSTRUCT, *PTRACKSTRUCT;
  49. PTRACKSTRUCT TrackHead = NULL;
  50. #define TRACK_SIGNATURE 0x30405060
  51. DWORD
  52. pDebugHeapValidatePtrUnlocked (
  53. HANDLE hHeap,
  54. PCVOID CallerPtr,
  55. PCSTR File,
  56. DWORD Line
  57. );
  58. //
  59. // The following pointer can be used to help identify memory leak sources.
  60. // It is copied to the memory tracking log.
  61. //
  62. PCSTR g_TrackComment;
  63. PCSTR g_TrackFile;
  64. UINT g_TrackLine;
  65. INT g_UseCount;
  66. UINT g_DisableTrackComment = 0;
  67. VOID
  68. DisableTrackComment (
  69. VOID
  70. )
  71. {
  72. g_DisableTrackComment ++;
  73. }
  74. VOID
  75. EnableTrackComment (
  76. VOID
  77. )
  78. {
  79. if (g_DisableTrackComment > 0) {
  80. g_DisableTrackComment --;
  81. }
  82. }
  83. DWORD
  84. SetTrackComment (
  85. PCSTR Msg,
  86. PCSTR File,
  87. UINT Line
  88. )
  89. {
  90. static CHAR Buffer[1024];
  91. static CHAR FileCopy[1024];
  92. if (g_DisableTrackComment > 0) {
  93. return 0;
  94. }
  95. if (g_UseCount > 0) {
  96. g_UseCount++;
  97. return 0;
  98. }
  99. if (Msg) {
  100. wsprintfA (Buffer, "%s (%s line %u)", Msg, File, Line);
  101. } else {
  102. wsprintfA (Buffer, "%s line %u", File, Line);
  103. }
  104. StringCopyA (FileCopy, File);
  105. g_TrackFile = FileCopy;
  106. g_TrackLine = Line;
  107. g_TrackComment = Buffer;
  108. g_UseCount = 1;
  109. return 0;
  110. }
  111. DWORD
  112. ClrTrackComment (
  113. VOID
  114. )
  115. {
  116. if (g_DisableTrackComment > 0) {
  117. return 0;
  118. }
  119. g_UseCount--;
  120. if (!g_UseCount) {
  121. g_TrackComment=NULL;
  122. }
  123. return 0;
  124. }
  125. VOID
  126. pTrackInsert (
  127. PCSTR File,
  128. DWORD Line,
  129. DWORD Size,
  130. PTRACKSTRUCT p
  131. )
  132. {
  133. p->Signature = TRACK_SIGNATURE;
  134. p->File = File;
  135. p->Line = Line;
  136. p->Size = Size;
  137. p->Comment = g_TrackComment ? SafeHeapAlloc (g_hHeap, 0, SizeOfStringA (g_TrackComment)) : NULL;
  138. p->PrevAlloc = NULL;
  139. p->NextAlloc = TrackHead;
  140. if (p->Comment) {
  141. StringCopyA (p->Comment, g_TrackComment);
  142. }
  143. if (TrackHead) {
  144. TrackHead->PrevAlloc = p;
  145. }
  146. TrackHead = p;
  147. }
  148. VOID
  149. pTrackDelete (
  150. PTRACKSTRUCT p
  151. )
  152. {
  153. if (p->Signature != TRACK_SIGNATURE) {
  154. DEBUGMSG ((DBG_WARNING, "A tracking signature is invalid. "
  155. "This suggests memory corruption."));
  156. return;
  157. }
  158. if (p->PrevAlloc) {
  159. p->PrevAlloc->NextAlloc = p->NextAlloc;
  160. } else {
  161. TrackHead = p->NextAlloc;
  162. }
  163. if (p->NextAlloc) {
  164. p->NextAlloc->PrevAlloc = p->PrevAlloc;
  165. }
  166. }
  167. VOID
  168. pWriteTrackLog (
  169. VOID
  170. )
  171. {
  172. HANDLE File;
  173. CHAR LineBuf[2048];
  174. PTRACKSTRUCT p;
  175. DWORD DontCare;
  176. DWORD Count;
  177. BOOL BadMem = FALSE;
  178. CHAR TempPath[MAX_TCHAR_PATH];
  179. CHAR memtrackLogPath[] = "c:\\memtrack.log";
  180. if (!TrackHead) {
  181. return;
  182. }
  183. if (ISPC98()) {
  184. GetSystemDirectory(TempPath, MAX_TCHAR_PATH);
  185. memtrackLogPath[0] = TempPath[0];
  186. }
  187. File = CreateFileA (memtrackLogPath, GENERIC_WRITE, 0, NULL,
  188. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
  189. );
  190. if (File != INVALID_HANDLE_VALUE) {
  191. Count = 0;
  192. __try {
  193. for (p = TrackHead ; p ; p = p->NextAlloc) {
  194. Count++;
  195. __try {
  196. if (p->Comment) {
  197. wsprintfA (LineBuf, "%s line %u\r\n %s\r\n\r\n", p->File, p->Line, p->Comment);
  198. } else {
  199. wsprintfA (LineBuf, "%s line %u\r\n\r\n", p->File, p->Line);
  200. }
  201. }
  202. __except (TRUE) {
  203. wsprintfA (LineBuf, "Address %Xh was freed, but not by MemFree!!\r\n", p);
  204. BadMem = TRUE;
  205. }
  206. WriteFile (File, LineBuf, ByteCountA (LineBuf), &DontCare, NULL);
  207. if (BadMem) {
  208. break;
  209. }
  210. }
  211. }
  212. __except (TRUE) {
  213. }
  214. wsprintfA (LineBuf, "\r\n%i item%s allocated but not freed.\r\n", Count, Count == 1 ? "":"s");
  215. WriteFile (File, LineBuf, ByteCountA (LineBuf), &DontCare, NULL);
  216. CloseHandle (File);
  217. }
  218. }
  219. typedef struct {
  220. ALLOCTYPE Type;
  221. PVOID Ptr;
  222. PCSTR FileName;
  223. UINT Line;
  224. } ALLOCATION_ITEM, *PALLOCATION_ITEM;
  225. GROWBUFFER g_AllocationList;
  226. PVOID g_FirstDeletedAlloc;
  227. VOID
  228. InitAllocationTracking (
  229. VOID
  230. )
  231. {
  232. ZeroMemory (&g_AllocationList, sizeof (g_AllocationList));
  233. g_AllocationList.GrowSize = 65536;
  234. g_FirstDeletedAlloc = NULL;
  235. }
  236. VOID
  237. FreeAllocationTracking (
  238. VOID
  239. )
  240. {
  241. UINT Size;
  242. UINT u;
  243. PALLOCATION_ITEM Item;
  244. GROWBUFFER Msg = GROWBUF_INIT;
  245. CHAR Text[1024];
  246. PSTR p;
  247. UINT Bytes;
  248. Size = g_AllocationList.End / sizeof (ALLOCATION_ITEM);;
  249. for (u = 0 ; u < Size ; u++) {
  250. Item = (PALLOCATION_ITEM) g_AllocationList.Buf + u;
  251. if (!Item->FileName) {
  252. continue;
  253. }
  254. Bytes = wsprintfA (Text, "%s line %u\r\n", Item->FileName, Item->Line);
  255. p = (PSTR) RealGrowBuffer (&Msg, Bytes);
  256. if (p) {
  257. CopyMemory (p, Text, Bytes);
  258. }
  259. }
  260. if (Msg.End) {
  261. p = (PSTR) RealGrowBuffer (&Msg, 1);
  262. if (p) {
  263. *p = 0;
  264. DEBUGMSGA (("Leaks", "%s", Msg.Buf));
  265. }
  266. FreeGrowBuffer (&Msg);
  267. }
  268. FreeGrowBuffer (&g_AllocationList);
  269. g_FirstDeletedAlloc = NULL;
  270. // Intentional leak -- who cares about track memory
  271. g_TrackPoolDelHead = NULL;
  272. g_TrackPool = NULL;
  273. }
  274. PTRACKBUCKETITEM
  275. pAllocTrackBucketItem (
  276. VOID
  277. )
  278. {
  279. PTRACKBUCKETITEM BucketItem;
  280. if (g_TrackPoolDelHead) {
  281. BucketItem = g_TrackPoolDelHead;
  282. g_TrackPoolDelHead = BucketItem->Next;
  283. } else {
  284. if (!g_TrackPool || g_TrackPool->Count == BUCKET_ITEMS_PER_POOL) {
  285. g_TrackPool = (PTRACKBUCKETPOOL) SafeHeapAlloc (g_hHeap, 0, sizeof (TRACKBUCKETPOOL));
  286. if (!g_TrackPool) {
  287. return NULL;
  288. }
  289. g_TrackPool->Count = 0;
  290. }
  291. BucketItem = g_TrackPool->Items + g_TrackPool->Count;
  292. g_TrackPool->Count++;
  293. }
  294. return BucketItem;
  295. }
  296. VOID
  297. pFreeTrackBucketItem (
  298. PTRACKBUCKETITEM BucketItem
  299. )
  300. {
  301. BucketItem->Next = g_TrackPoolDelHead;
  302. g_TrackPoolDelHead = BucketItem;
  303. }
  304. DWORD
  305. pComputeTrackHashVal (
  306. IN ALLOCTYPE Type,
  307. IN PVOID Ptr
  308. )
  309. {
  310. DWORD Hash;
  311. Hash = (DWORD) (Type << 16) ^ (DWORD) Ptr;
  312. return Hash % TRACK_BUCKETS;
  313. }
  314. VOID
  315. pTrackHashTableInsert (
  316. IN PBYTE Base,
  317. IN ALLOCATION_ITEM_OFFSET ItemOffset
  318. )
  319. {
  320. DWORD Hash;
  321. PTRACKBUCKETITEM BucketItem;
  322. PALLOCATION_ITEM Item;
  323. Item = (PALLOCATION_ITEM) (Base + ItemOffset);
  324. Hash = pComputeTrackHashVal (Item->Type, Item->Ptr);
  325. BucketItem = pAllocTrackBucketItem();
  326. if (!BucketItem) {
  327. DEBUGMSG ((DBG_WHOOPS, "pTrackHashTableInsert failed to alloc memory"));
  328. return;
  329. }
  330. BucketItem->Prev = NULL;
  331. BucketItem->Next = g_TrackBuckets[Hash];
  332. BucketItem->Type = Item->Type;
  333. BucketItem->Ptr = Item->Ptr;
  334. BucketItem->ItemOffset = ItemOffset;
  335. if (BucketItem->Next) {
  336. BucketItem->Next->Prev = BucketItem;
  337. }
  338. g_TrackBuckets[Hash] = BucketItem;
  339. }
  340. VOID
  341. pTrackHashTableDelete (
  342. IN PTRACKBUCKETITEM BucketItem
  343. )
  344. {
  345. DWORD Hash;
  346. Hash = pComputeTrackHashVal (BucketItem->Type, BucketItem->Ptr);
  347. if (BucketItem->Prev) {
  348. BucketItem->Prev->Next = BucketItem->Next;
  349. } else {
  350. g_TrackBuckets[Hash] = BucketItem->Next;
  351. }
  352. if (BucketItem->Next) {
  353. BucketItem->Next->Prev = BucketItem->Prev;
  354. }
  355. pFreeTrackBucketItem (BucketItem);
  356. }
  357. PTRACKBUCKETITEM
  358. pTrackHashTableFind (
  359. IN ALLOCTYPE Type,
  360. IN PVOID Ptr
  361. )
  362. {
  363. PTRACKBUCKETITEM BucketItem;
  364. DWORD Hash;
  365. Hash = pComputeTrackHashVal (Type, Ptr);
  366. BucketItem = g_TrackBuckets[Hash];
  367. while (BucketItem) {
  368. if (BucketItem->Type == Type && BucketItem->Ptr == Ptr) {
  369. return BucketItem;
  370. }
  371. BucketItem = BucketItem->Next;
  372. }
  373. return NULL;
  374. }
  375. VOID
  376. DebugRegisterAllocation (
  377. IN ALLOCTYPE Type,
  378. IN PVOID Ptr,
  379. IN PCSTR File,
  380. IN UINT Line
  381. )
  382. {
  383. PALLOCATION_ITEM Item;
  384. MYASSERT (File);
  385. if (!g_FirstDeletedAlloc) {
  386. Item = (PALLOCATION_ITEM) RealGrowBuffer (&g_AllocationList,sizeof(ALLOCATION_ITEM));
  387. } else {
  388. Item = (PALLOCATION_ITEM) g_FirstDeletedAlloc;
  389. g_FirstDeletedAlloc = Item->Ptr;
  390. }
  391. if (Item) {
  392. Item->Type = Type;
  393. Item->Ptr = Ptr;
  394. Item->FileName = File;
  395. Item->Line = Line;
  396. pTrackHashTableInsert (g_AllocationList.Buf, (PBYTE) Item - g_AllocationList.Buf);
  397. }
  398. }
  399. VOID
  400. DebugUnregisterAllocation (
  401. IN ALLOCTYPE Type,
  402. IN PVOID Ptr
  403. )
  404. {
  405. PALLOCATION_ITEM Item;
  406. PTRACKBUCKETITEM BucketItem;
  407. BucketItem = pTrackHashTableFind (Type, Ptr);
  408. if (!g_AllocationList.Buf) {
  409. DEBUGMSG ((DBG_WARNING, "Unregister allocation: Allocation buffer already freed"));
  410. return;
  411. }
  412. if (BucketItem) {
  413. Item = (PALLOCATION_ITEM) (g_AllocationList.Buf + BucketItem->ItemOffset);
  414. Item->FileName = NULL;
  415. Item->Type = -1;
  416. Item->Ptr = g_FirstDeletedAlloc;
  417. g_FirstDeletedAlloc = Item;
  418. pTrackHashTableDelete (BucketItem);
  419. } else {
  420. DEBUGMSG ((DBG_WARNING, "Unregister allocation: Pointer not registered"));
  421. }
  422. }
  423. //
  424. // File and Line settings
  425. //
  426. static PCSTR g_File;
  427. static DWORD g_Line;
  428. void
  429. HeapCallFailed (
  430. PCSTR Msg,
  431. PCSTR File,
  432. DWORD Line
  433. )
  434. {
  435. CHAR Msg2[2048];
  436. wsprintfA (Msg2, "Error in %s line %u\n\n", File, Line);
  437. strcat (Msg2, Msg);
  438. strcat (Msg2, "\n\nBreak execution now?");
  439. if (IDYES == MessageBoxA (GetFocus(), Msg2, "Heap Call Failed", MB_YESNO|MB_APPLMODAL)) {
  440. DebugBreak ();
  441. }
  442. }
  443. #define INVALID_PTR 0xffffffff
  444. DWORD
  445. DebugHeapValidatePtr (
  446. HANDLE hHeap,
  447. PCVOID CallerPtr,
  448. PCSTR File,
  449. DWORD Line
  450. )
  451. {
  452. DWORD rc;
  453. EnterCriticalSection (&g_MemAllocCs);
  454. rc = pDebugHeapValidatePtrUnlocked (hHeap, CallerPtr, File, Line);
  455. LeaveCriticalSection (&g_MemAllocCs);
  456. return rc;
  457. }
  458. DWORD
  459. pDebugHeapValidatePtrUnlocked (
  460. HANDLE hHeap,
  461. PCVOID CallerPtr,
  462. PCSTR File,
  463. DWORD Line
  464. )
  465. {
  466. DWORD dwSize;
  467. PCVOID RealPtr;
  468. DWORD SizeAdjust;
  469. SizeAdjust = sizeof (TRACKSTRUCT);
  470. RealPtr = (PCVOID) ((PBYTE) CallerPtr - SizeAdjust);
  471. if (IsBadWritePtr ((PBYTE) RealPtr - 8, 8)) {
  472. CHAR BadPtrMsg[256];
  473. wsprintfA (
  474. BadPtrMsg,
  475. "Attempt to free memory at 0x%08x. This address is not valid.",
  476. CallerPtr
  477. );
  478. HeapCallFailed (BadPtrMsg, File, Line);
  479. return INVALID_PTR;
  480. }
  481. dwSize = HeapSize (hHeap, 0, RealPtr);
  482. if (dwSize == 0xffffffff) {
  483. CHAR BadPtrMsg[256];
  484. wsprintfA (
  485. BadPtrMsg,
  486. "Attempt to free memory at 0x%08x. "
  487. "This address is not the start of a memory block.",
  488. CallerPtr
  489. );
  490. HeapCallFailed (BadPtrMsg, File, Line);
  491. return INVALID_PTR;
  492. }
  493. return dwSize;
  494. }
  495. //
  496. // Heap debug statistics
  497. //
  498. static DWORD g_dwTotalBytesAllocated = 0;
  499. static DWORD g_dwMaxBytesInUse = 0;
  500. static DWORD g_dwHeapAllocs = 0;
  501. static DWORD g_dwHeapReAllocs = 0;
  502. static DWORD g_dwHeapFrees = 0;
  503. static DWORD g_dwHeapAllocFails = 0;
  504. static DWORD g_dwHeapReAllocFails = 0;
  505. static DWORD g_dwHeapFreeFails = 0;
  506. #define TRAIL_SIG 0x708aa210
  507. PVOID
  508. DebugHeapAlloc (
  509. PCSTR File,
  510. DWORD Line,
  511. HANDLE hHeap,
  512. DWORD Flags,
  513. DWORD BytesToAlloc
  514. )
  515. {
  516. PVOID RealPtr;
  517. PVOID ReturnPtr = NULL;
  518. DWORD SizeAdjust;
  519. DWORD TrackStructSize;
  520. DWORD OrgError;
  521. EnterCriticalSection (&g_MemAllocCs);
  522. __try {
  523. OrgError = GetLastError();
  524. SizeAdjust = sizeof (TRACKSTRUCT) + sizeof (DWORD);
  525. TrackStructSize = sizeof (TRACKSTRUCT);
  526. if (!HeapValidate (hHeap, 0, NULL)) {
  527. HeapCallFailed ("Heap is corrupt!", File, Line);
  528. g_dwHeapAllocFails++;
  529. __leave;
  530. }
  531. RealPtr = SafeHeapAlloc(hHeap, Flags, BytesToAlloc + SizeAdjust);
  532. if (RealPtr) {
  533. g_dwHeapAllocs++;
  534. g_dwTotalBytesAllocated += HeapSize (hHeap, 0, RealPtr);
  535. g_dwMaxBytesInUse = max (g_dwMaxBytesInUse, g_dwTotalBytesAllocated);
  536. pTrackInsert (File, Line, BytesToAlloc, (PTRACKSTRUCT) RealPtr);
  537. *((PDWORD) ((PBYTE) RealPtr + TrackStructSize + BytesToAlloc)) = TRAIL_SIG;
  538. }
  539. else {
  540. g_dwHeapAllocFails++;
  541. }
  542. if (RealPtr) {
  543. ReturnPtr = (PVOID) ((PBYTE) RealPtr + TrackStructSize);
  544. }
  545. if (ReturnPtr && !(Flags & HEAP_ZERO_MEMORY)) {
  546. FillMemory (ReturnPtr, BytesToAlloc, 0xAA);
  547. }
  548. if (RealPtr) {
  549. SetLastError(OrgError);
  550. }
  551. }
  552. __finally {
  553. LeaveCriticalSection (&g_MemAllocCs);
  554. }
  555. return ReturnPtr;
  556. }
  557. PVOID
  558. DebugHeapReAlloc (
  559. PCSTR File,
  560. DWORD Line,
  561. HANDLE hHeap,
  562. DWORD Flags,
  563. PCVOID CallerPtr,
  564. DWORD BytesToAlloc
  565. )
  566. {
  567. DWORD dwLastSize;
  568. PVOID NewRealPtr;
  569. PCVOID RealPtr;
  570. PVOID ReturnPtr = NULL;
  571. DWORD SizeAdjust;
  572. DWORD OrgError;
  573. DWORD TrackStructSize;
  574. DWORD OrgSize;
  575. PTRACKSTRUCT pts = NULL;
  576. EnterCriticalSection (&g_MemAllocCs);
  577. __try {
  578. OrgError = GetLastError();
  579. SizeAdjust = sizeof (TRACKSTRUCT) + sizeof (DWORD);
  580. TrackStructSize = sizeof (TRACKSTRUCT);
  581. RealPtr = (PCVOID) ((PBYTE) CallerPtr - TrackStructSize);
  582. pts = (PTRACKSTRUCT) RealPtr;
  583. OrgSize = pts->Size;
  584. if (!HeapValidate (hHeap, 0, NULL)) {
  585. HeapCallFailed ("Heap is corrupt!", File, Line);
  586. g_dwHeapReAllocFails++;
  587. __leave;
  588. }
  589. dwLastSize = pDebugHeapValidatePtrUnlocked (hHeap, CallerPtr, File, Line);
  590. if (dwLastSize == INVALID_PTR) {
  591. g_dwHeapReAllocFails++;
  592. __leave;
  593. }
  594. pTrackDelete (pts);
  595. NewRealPtr = SafeHeapReAlloc (hHeap, Flags, (PVOID) RealPtr, BytesToAlloc + SizeAdjust);
  596. if (NewRealPtr) {
  597. g_dwHeapReAllocs++;
  598. g_dwTotalBytesAllocated -= dwLastSize;
  599. g_dwTotalBytesAllocated += HeapSize (hHeap, 0, NewRealPtr);
  600. g_dwMaxBytesInUse = max (g_dwMaxBytesInUse, g_dwTotalBytesAllocated);
  601. pTrackInsert (File, Line, BytesToAlloc, (PTRACKSTRUCT) NewRealPtr);
  602. *((PDWORD) ((PBYTE) NewRealPtr + TrackStructSize + BytesToAlloc)) = TRAIL_SIG;
  603. }
  604. else {
  605. g_dwHeapReAllocFails++;
  606. // Put original address back in
  607. pTrackInsert (
  608. pts->File,
  609. pts->Line,
  610. pts->Size,
  611. pts
  612. );
  613. }
  614. if (NewRealPtr) {
  615. ReturnPtr = (PVOID) ((PBYTE) NewRealPtr + TrackStructSize);
  616. }
  617. if (ReturnPtr && BytesToAlloc > OrgSize && !(Flags & HEAP_ZERO_MEMORY)) {
  618. FillMemory ((PBYTE) ReturnPtr + OrgSize, BytesToAlloc - OrgSize, 0xAA);
  619. }
  620. if (ReturnPtr) {
  621. SetLastError (OrgError);
  622. }
  623. }
  624. __finally {
  625. LeaveCriticalSection (&g_MemAllocCs);
  626. }
  627. return ReturnPtr;
  628. }
  629. BOOL
  630. DebugHeapFree (
  631. PCSTR File,
  632. DWORD Line,
  633. HANDLE hHeap,
  634. DWORD Flags,
  635. PCVOID CallerPtr
  636. )
  637. {
  638. DWORD dwSize;
  639. PCVOID RealPtr;
  640. DWORD SizeAdjust;
  641. DWORD OrgError;
  642. BOOL Result = FALSE;
  643. PTRACKSTRUCT pts = NULL;
  644. EnterCriticalSection (&g_MemAllocCs);
  645. __try {
  646. OrgError = GetLastError();
  647. SizeAdjust = sizeof (TRACKSTRUCT);
  648. RealPtr = (PCVOID) ((PBYTE) CallerPtr - SizeAdjust);
  649. pts = (PTRACKSTRUCT) RealPtr;
  650. if (*((PDWORD) ((PBYTE) CallerPtr + pts->Size)) != TRAIL_SIG) {
  651. HeapCallFailed ("Heap tag was overwritten!", File, Line);
  652. __leave;
  653. }
  654. if (!HeapValidate (hHeap, 0, NULL)) {
  655. HeapCallFailed ("Heap is corrupt!", File, Line);
  656. g_dwHeapFreeFails++;
  657. __leave;
  658. }
  659. dwSize = pDebugHeapValidatePtrUnlocked (hHeap, CallerPtr, File, Line);
  660. if (dwSize == INVALID_PTR) {
  661. g_dwHeapFreeFails++;
  662. __leave;
  663. }
  664. pTrackDelete ((PTRACKSTRUCT) RealPtr);
  665. if (!HeapFree (hHeap, Flags, (PVOID) RealPtr)) {
  666. CHAR BadPtrMsg[256];
  667. wsprintf (BadPtrMsg,
  668. "Attempt to free memory at 0x%08x with flags 0x%08x. "
  669. "HeapFree() failed.",
  670. CallerPtr, Flags);
  671. HeapCallFailed (BadPtrMsg, File, Line);
  672. g_dwHeapFreeFails++;
  673. __leave;
  674. }
  675. g_dwHeapFrees++;
  676. if (g_dwTotalBytesAllocated < dwSize) {
  677. DEBUGMSG ((DBG_WARNING, "Total bytes allocated is less than amount being freed. "
  678. "This suggests memory corruption."));
  679. g_dwTotalBytesAllocated = 0;
  680. } else {
  681. g_dwTotalBytesAllocated -= dwSize;
  682. }
  683. SetLastError (OrgError);
  684. Result = TRUE;
  685. }
  686. __finally {
  687. LeaveCriticalSection (&g_MemAllocCs);
  688. }
  689. return Result;
  690. }
  691. VOID
  692. DumpHeapStats (
  693. VOID
  694. )
  695. {
  696. CHAR OutputMsg[4096];
  697. pWriteTrackLog();
  698. wsprintfA (OutputMsg,
  699. "Bytes currently allocated: %u\n"
  700. "Peak bytes allocated: %u\n"
  701. "Allocation count: %u\n"
  702. "Reallocation count: %u\n"
  703. "Free count: %u\n",
  704. g_dwTotalBytesAllocated,
  705. g_dwMaxBytesInUse,
  706. g_dwHeapAllocs,
  707. g_dwHeapReAllocs,
  708. g_dwHeapFrees
  709. );
  710. if (g_dwHeapAllocFails) {
  711. wsprintfA (strchr (OutputMsg, 0),
  712. "***Allocation failures: %u\n",
  713. g_dwHeapAllocFails);
  714. }
  715. if (g_dwHeapReAllocFails) {
  716. wsprintfA (strchr (OutputMsg, 0),
  717. "***Reallocation failures: %u\n",
  718. g_dwHeapReAllocFails);
  719. }
  720. if (g_dwHeapFreeFails) {
  721. wsprintfA (strchr (OutputMsg, 0),
  722. "***Free failures: %u\n",
  723. g_dwHeapFreeFails);
  724. }
  725. DEBUGMSG ((DBG_STATS, "%s", OutputMsg));
  726. #ifdef CONSOLE
  727. printf ("%s", OutputMsg);
  728. #else // i.e. ifndef CONSOLE
  729. #if 0
  730. if (0) {
  731. PROCESS_HEAP_ENTRY he;
  732. CHAR FlagMsg[256];
  733. ZeroMemory (&he, sizeof (he));
  734. while (HeapWalk (g_hHeap, &he)) {
  735. FlagMsg[0] = 0;
  736. if (he.wFlags & PROCESS_HEAP_REGION) {
  737. strcpy (FlagMsg, "PROCESS_HEAP_REGION");
  738. }
  739. if (he.wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) {
  740. if (FlagMsg[0])
  741. strcat (FlagMsg, ", ");
  742. strcat (FlagMsg, "PROCESS_HEAP_UNCOMMITTED_RANGE");
  743. }
  744. if (he.wFlags & PROCESS_HEAP_ENTRY_BUSY) {
  745. if (FlagMsg[0])
  746. strcat (FlagMsg, ", ");
  747. strcat (FlagMsg, "PROCESS_HEAP_ENTRY_BUSY");
  748. }
  749. if (he.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE) {
  750. if (FlagMsg[0])
  751. strcat (FlagMsg, ", ");
  752. strcat (FlagMsg, "PROCESS_HEAP_ENTRY_MOVEABLE");
  753. }
  754. if (he.wFlags & PROCESS_HEAP_ENTRY_DDESHARE) {
  755. if (FlagMsg[0])
  756. strcat (FlagMsg, ", ");
  757. strcat (FlagMsg, "PROCESS_HEAP_ENTRY_DDESHARE");
  758. }
  759. wsprintfA (OutputMsg,
  760. "Address of Data: %Xh\n"
  761. "Size of Data: %u byte%s\n"
  762. "OS Overhead: %u byte%s\n"
  763. "Region index: %u\n"
  764. "Flags: %s\n\n"
  765. "Examine Data?",
  766. he.lpData,
  767. he.cbData, he.cbData == 1 ? "" : "s",
  768. he.cbOverhead, he.cbOverhead == 1 ? "" : "s",
  769. he.iRegionIndex,
  770. FlagMsg
  771. );
  772. rc = MessageBoxA (GetFocus(), OutputMsg, "Memory Allocation Statistics", MB_YESNOCANCEL|MB_APPLMODAL|MB_SETFOREGROUND);
  773. if (rc == IDCANCEL) {
  774. break;
  775. }
  776. if (rc == IDYES) {
  777. int i, j, k, l;
  778. PBYTE p;
  779. PSTR p2;
  780. OutputMsg[0] = 0;
  781. p = he.lpData;
  782. p2 = OutputMsg;
  783. j = min (256, he.cbData);
  784. for (i = 0 ; i < j ; i += 16) {
  785. l = i + 16;
  786. for (k = i ; k < l ; k++) {
  787. if (k < j) {
  788. wsprintfA (p2, "%02X ", (DWORD) (p[k]));
  789. } else {
  790. wsprintfA (p2, " ");
  791. }
  792. p2 = strchr (p2, 0);
  793. }
  794. l = min (l, j);
  795. for (k = i ; k < l ; k++) {
  796. if (isprint (p[k])) {
  797. *p2 = (CHAR) p[k];
  798. } else {
  799. *p2 = '.';
  800. }
  801. p2++;
  802. }
  803. *p2 = '\n';
  804. p2++;
  805. *p2 = 0;
  806. }
  807. MessageBoxA (GetFocus(), OutputMsg, "Memory Allocation Statistics", MB_OK|MB_APPLMODAL|MB_SETFOREGROUND);
  808. }
  809. }
  810. }
  811. #endif // #if 0
  812. #endif // #ifndef CONSOLE
  813. }
  814. void
  815. DebugHeapCheck (
  816. PCSTR File,
  817. DWORD Line,
  818. HANDLE hHeap
  819. )
  820. {
  821. EnterCriticalSection (&g_MemAllocCs);
  822. if (!HeapValidate (hHeap, 0, NULL)) {
  823. HeapCallFailed ("HeapCheck failed: Heap is corrupt!", File, Line);
  824. }
  825. LeaveCriticalSection (&g_MemAllocCs);
  826. }
  827. #endif