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.

869 lines
18 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. basemem.c
  5. Abstract:
  6. Implements macros and declares functions for basic allocation functions.
  7. Consolidated into this file from debug.c and main.c
  8. Author:
  9. Marc R. Whitten (marcw) 09-Sep-1999
  10. Revision History:
  11. --*/
  12. #include "pch.h"
  13. //
  14. // Includes
  15. //
  16. #include "utilsp.h"
  17. //
  18. // Constants
  19. //
  20. #ifdef DEBUG
  21. #define TRAIL_SIG 0x708aa210
  22. #define TRACK_SIGNATURE 0x30405060
  23. #endif
  24. //
  25. // Macros
  26. //
  27. #define REUSE_SIZE_PTR(ptr) ((PDWORD) ((PBYTE) ptr - sizeof (DWORD)))
  28. #define REUSE_TAG_PTR(ptr) ((PDWORD) ((PBYTE) ptr + (*REUSE_SIZE_PTR(ptr))))
  29. //
  30. // Types
  31. //
  32. #ifdef DEBUG
  33. typedef struct _tagTRACKSTRUCT {
  34. DWORD Signature;
  35. PCSTR File;
  36. DWORD Line;
  37. SIZE_T Size;
  38. PSTR Comment;
  39. PCSTR CallerFile;
  40. DWORD CallerLine;
  41. struct _tagTRACKSTRUCT *PrevAlloc;
  42. struct _tagTRACKSTRUCT *NextAlloc;
  43. } TRACKSTRUCT, *PTRACKSTRUCT;
  44. #endif
  45. //
  46. // Globals
  47. //
  48. #ifdef DEBUG
  49. PTRACKSTRUCT g_TrackHead = NULL;
  50. #endif
  51. //
  52. // Heap debug statistics
  53. //
  54. static SIZE_T g_TotalBytesAllocated = 0;
  55. static SIZE_T g_MaxBytesInUse = 0;
  56. static SIZE_T g_HeapAllocs = 0;
  57. static SIZE_T g_HeapReAllocs = 0;
  58. static SIZE_T g_HeapFrees = 0;
  59. static SIZE_T g_HeapAllocFails = 0;
  60. static SIZE_T g_HeapReAllocFails = 0;
  61. static SIZE_T g_HeapFreeFails = 0;
  62. //
  63. // Out of memory string -- loaded at initialization
  64. //
  65. PCSTR g_OutOfMemoryString = NULL;
  66. PCSTR g_OutOfMemoryRetry = NULL;
  67. HWND g_OutOfMemoryParentWnd;
  68. //
  69. // Macro expansion list
  70. //
  71. // None
  72. //
  73. // Private function prototypes
  74. //
  75. #ifdef DEBUG
  76. SIZE_T
  77. pDebugHeapValidatePtrUnlocked (
  78. HANDLE hHeap,
  79. PCVOID CallerPtr,
  80. PCSTR File,
  81. DWORD Line
  82. );
  83. VOID
  84. pTrackInsert (
  85. PCSTR File,
  86. DWORD Line,
  87. SIZE_T Size,
  88. PTRACKSTRUCT p
  89. );
  90. VOID
  91. pTrackDelete (
  92. PTRACKSTRUCT p
  93. );
  94. VOID
  95. pWriteTrackLog (
  96. VOID
  97. );
  98. #endif
  99. //
  100. // Macro expansion definition
  101. //
  102. // None
  103. //
  104. // Code
  105. //
  106. void
  107. HeapCallFailed (
  108. PCSTR Msg,
  109. PCSTR File,
  110. DWORD Line
  111. )
  112. {
  113. CHAR Msg2[2048];
  114. wsprintfA (Msg2, "Error in %s line %u\n\n", File, Line);
  115. strcat (Msg2, Msg);
  116. strcat (Msg2, "\n\nBreak execution now?");
  117. if (IDYES == MessageBoxA (GetFocus(), Msg2, "Heap Call Failed", MB_YESNO|MB_APPLMODAL)) {
  118. DebugBreak ();
  119. }
  120. }
  121. #ifdef DEBUG
  122. SIZE_T
  123. DebugHeapValidatePtr (
  124. HANDLE hHeap,
  125. PCVOID CallerPtr,
  126. PCSTR File,
  127. DWORD Line
  128. )
  129. {
  130. SIZE_T rc;
  131. EnterOurCriticalSection (&g_MemAllocCs);
  132. rc = pDebugHeapValidatePtrUnlocked (hHeap, CallerPtr, File, Line);
  133. LeaveOurCriticalSection (&g_MemAllocCs);
  134. return rc;
  135. }
  136. SIZE_T
  137. pDebugHeapValidatePtrUnlocked (
  138. HANDLE hHeap,
  139. PCVOID CallerPtr,
  140. PCSTR File,
  141. DWORD Line
  142. )
  143. {
  144. SIZE_T size;
  145. PCVOID RealPtr;
  146. SIZE_T SizeAdjust;
  147. SizeAdjust = sizeof (TRACKSTRUCT);
  148. RealPtr = (PCVOID) ((PBYTE) CallerPtr - SizeAdjust);
  149. if (IsBadWritePtr ((PBYTE) RealPtr - 8, 8)) {
  150. CHAR BadPtrMsg[256];
  151. //lint --e(572)
  152. wsprintfA (
  153. BadPtrMsg,
  154. "Attempt to free memory at 0x%08x%08x. This address is not valid.",
  155. (DWORD)((UBINT)CallerPtr >> 32),
  156. (DWORD)(UBINT)CallerPtr
  157. );
  158. HeapCallFailed (BadPtrMsg, File, Line);
  159. return (SIZE_T)INVALID_PTR;
  160. }
  161. size = HeapSize (hHeap, 0, RealPtr);
  162. if (size == (SIZE_T)-1) {
  163. CHAR BadPtrMsg[256];
  164. //lint --e(572)
  165. wsprintfA (
  166. BadPtrMsg,
  167. "Attempt to free memory at 0x%08x%08x. "
  168. "This address is not the start of a memory block.",
  169. (DWORD)((UBINT)CallerPtr >> 32),
  170. (DWORD)(UBINT)CallerPtr
  171. );
  172. HeapCallFailed (BadPtrMsg, File, Line);
  173. return (SIZE_T)INVALID_PTR;
  174. }
  175. return size;
  176. }
  177. PVOID
  178. DebugHeapAlloc (
  179. PCSTR File,
  180. DWORD Line,
  181. HANDLE hHeap,
  182. DWORD Flags,
  183. SIZE_T BytesToAlloc
  184. )
  185. {
  186. PVOID RealPtr;
  187. PVOID ReturnPtr = NULL;
  188. DWORD SizeAdjust;
  189. DWORD TrackStructSize;
  190. DWORD OrgError;
  191. EnterOurCriticalSection (&g_MemAllocCs);
  192. __try {
  193. OrgError = GetLastError();
  194. SizeAdjust = sizeof (TRACKSTRUCT) + sizeof (DWORD);
  195. TrackStructSize = sizeof (TRACKSTRUCT);
  196. if (!HeapValidate (hHeap, 0, NULL)) {
  197. HeapCallFailed ("Heap is corrupt!", File, Line);
  198. g_HeapAllocFails++;
  199. __leave;
  200. }
  201. RealPtr = SafeHeapAlloc(hHeap, Flags, BytesToAlloc + SizeAdjust);
  202. if (RealPtr) {
  203. g_HeapAllocs++;
  204. g_TotalBytesAllocated += HeapSize (hHeap, 0, RealPtr);
  205. g_MaxBytesInUse = max (g_MaxBytesInUse, g_TotalBytesAllocated);
  206. pTrackInsert (File, Line, BytesToAlloc, (PTRACKSTRUCT) RealPtr);
  207. *((PDWORD) ((PBYTE) RealPtr + TrackStructSize + BytesToAlloc)) = TRAIL_SIG;
  208. }
  209. else {
  210. g_HeapAllocFails++;
  211. }
  212. if (RealPtr) {
  213. ReturnPtr = (PVOID) ((PBYTE) RealPtr + TrackStructSize);
  214. }
  215. if (ReturnPtr && !(Flags & HEAP_ZERO_MEMORY)) {
  216. FillMemory (ReturnPtr, BytesToAlloc, 0xAA);
  217. }
  218. if (RealPtr) {
  219. SetLastError(OrgError);
  220. }
  221. }
  222. __finally {
  223. LeaveOurCriticalSection (&g_MemAllocCs);
  224. }
  225. return ReturnPtr;
  226. }
  227. PVOID
  228. DebugHeapReAlloc (
  229. PCSTR File,
  230. DWORD Line,
  231. HANDLE hHeap,
  232. DWORD Flags,
  233. PCVOID CallerPtr,
  234. SIZE_T BytesToAlloc
  235. )
  236. {
  237. UBINT lastSize;
  238. PVOID NewRealPtr;
  239. PCVOID RealPtr;
  240. PVOID ReturnPtr = NULL;
  241. DWORD SizeAdjust;
  242. DWORD OrgError;
  243. DWORD TrackStructSize;
  244. SIZE_T OrgSize;
  245. PTRACKSTRUCT pts = NULL;
  246. EnterOurCriticalSection (&g_MemAllocCs);
  247. __try {
  248. OrgError = GetLastError();
  249. SizeAdjust = sizeof (TRACKSTRUCT) + sizeof (DWORD);
  250. TrackStructSize = sizeof (TRACKSTRUCT);
  251. RealPtr = (PCVOID) ((PBYTE) CallerPtr - TrackStructSize);
  252. pts = (PTRACKSTRUCT) RealPtr;
  253. OrgSize = pts->Size;
  254. if (!HeapValidate (hHeap, 0, NULL)) {
  255. HeapCallFailed ("Heap is corrupt!", File, Line);
  256. g_HeapReAllocFails++;
  257. __leave;
  258. }
  259. lastSize = pDebugHeapValidatePtrUnlocked (hHeap, CallerPtr, File, Line);
  260. if (lastSize == (UBINT)INVALID_PTR) {
  261. g_HeapReAllocFails++;
  262. __leave;
  263. }
  264. pTrackDelete (pts);
  265. NewRealPtr = SafeHeapReAlloc (hHeap, Flags, (PVOID) RealPtr, BytesToAlloc + SizeAdjust);
  266. if (NewRealPtr) {
  267. g_HeapReAllocs++;
  268. g_TotalBytesAllocated -= lastSize;
  269. g_TotalBytesAllocated += HeapSize (hHeap, 0, NewRealPtr);
  270. g_MaxBytesInUse = max (g_MaxBytesInUse, g_TotalBytesAllocated);
  271. pTrackInsert (File, Line, BytesToAlloc, (PTRACKSTRUCT) NewRealPtr);
  272. *((PDWORD) ((PBYTE) NewRealPtr + TrackStructSize + BytesToAlloc)) = TRAIL_SIG;
  273. }
  274. else {
  275. g_HeapReAllocFails++;
  276. // Put original address back in
  277. pTrackInsert (
  278. pts->File,
  279. pts->Line,
  280. pts->Size,
  281. pts
  282. );
  283. }
  284. if (NewRealPtr) {
  285. ReturnPtr = (PVOID) ((PBYTE) NewRealPtr + TrackStructSize);
  286. }
  287. if (ReturnPtr && BytesToAlloc > OrgSize && !(Flags & HEAP_ZERO_MEMORY)) {
  288. FillMemory ((PBYTE) ReturnPtr + OrgSize, BytesToAlloc - OrgSize, 0xAA);
  289. }
  290. if (ReturnPtr) {
  291. SetLastError (OrgError);
  292. }
  293. }
  294. __finally {
  295. LeaveOurCriticalSection (&g_MemAllocCs);
  296. }
  297. return ReturnPtr;
  298. }
  299. BOOL
  300. DebugHeapFree (
  301. PCSTR File,
  302. DWORD Line,
  303. HANDLE hHeap,
  304. DWORD Flags,
  305. PCVOID CallerPtr
  306. )
  307. {
  308. UBINT size;
  309. PCVOID RealPtr;
  310. DWORD SizeAdjust;
  311. DWORD OrgError;
  312. BOOL Result = FALSE;
  313. PTRACKSTRUCT pts = NULL;
  314. EnterOurCriticalSection (&g_MemAllocCs);
  315. __try {
  316. OrgError = GetLastError();
  317. SizeAdjust = sizeof (TRACKSTRUCT);
  318. RealPtr = (PCVOID) ((PBYTE) CallerPtr - SizeAdjust);
  319. pts = (PTRACKSTRUCT) RealPtr;
  320. if (*((PDWORD) ((PBYTE) CallerPtr + pts->Size)) != TRAIL_SIG) {
  321. HeapCallFailed ("Heap tag was overwritten!", File, Line);
  322. __leave;
  323. }
  324. if (!HeapValidate (hHeap, 0, NULL)) {
  325. HeapCallFailed ("Heap is corrupt!", File, Line);
  326. g_HeapFreeFails++;
  327. __leave;
  328. }
  329. size = pDebugHeapValidatePtrUnlocked (hHeap, CallerPtr, File, Line);
  330. if (size == (UBINT)INVALID_PTR) {
  331. g_HeapFreeFails++;
  332. __leave;
  333. }
  334. pTrackDelete ((PTRACKSTRUCT) RealPtr);
  335. if (!HeapFree (hHeap, Flags, (PVOID) RealPtr)) {
  336. CHAR BadPtrMsg[256];
  337. wsprintf (BadPtrMsg,
  338. "Attempt to free memory at 0x%08x with flags 0x%08x. "
  339. "HeapFree() failed.",
  340. CallerPtr, Flags);
  341. HeapCallFailed (BadPtrMsg, File, Line);
  342. g_HeapFreeFails++;
  343. __leave;
  344. }
  345. g_HeapFrees++;
  346. if (g_TotalBytesAllocated < size) {
  347. DEBUGMSG ((DBG_WARNING, "Total bytes allocated is less than amount being freed. "
  348. "This suggests memory corruption."));
  349. g_TotalBytesAllocated = 0;
  350. } else {
  351. g_TotalBytesAllocated -= size;
  352. }
  353. SetLastError (OrgError);
  354. Result = TRUE;
  355. }
  356. __finally {
  357. LeaveOurCriticalSection (&g_MemAllocCs);
  358. }
  359. return Result;
  360. }
  361. VOID
  362. DumpHeapStats (
  363. VOID
  364. )
  365. {
  366. CHAR OutputMsg[4096];
  367. pWriteTrackLog();
  368. wsprintfA (OutputMsg,
  369. "Bytes currently allocated: %u\n"
  370. "Peak bytes allocated: %u\n"
  371. "Allocation count: %u\n"
  372. "Reallocation count: %u\n"
  373. "Free count: %u\n",
  374. g_TotalBytesAllocated,
  375. g_MaxBytesInUse,
  376. g_HeapAllocs,
  377. g_HeapReAllocs,
  378. g_HeapFrees
  379. );
  380. if (g_HeapAllocFails) {
  381. wsprintfA (strchr (OutputMsg, 0),
  382. "***Allocation failures: %u\n",
  383. g_HeapAllocFails);
  384. }
  385. if (g_HeapReAllocFails) {
  386. wsprintfA (strchr (OutputMsg, 0),
  387. "***Reallocation failures: %u\n",
  388. g_HeapReAllocFails);
  389. }
  390. if (g_HeapFreeFails) {
  391. wsprintfA (strchr (OutputMsg, 0),
  392. "***Free failures: %u\n",
  393. g_HeapFreeFails);
  394. }
  395. DEBUGMSG ((DBG_STATS, "%s", OutputMsg));
  396. #ifdef CONSOLE
  397. printf ("%s", OutputMsg);
  398. #endif // #ifndef CONSOLE
  399. }
  400. void
  401. DebugHeapCheck (
  402. PCSTR File,
  403. DWORD Line,
  404. HANDLE hHeap
  405. )
  406. {
  407. EnterOurCriticalSection (&g_MemAllocCs);
  408. if (!HeapValidate (hHeap, 0, NULL)) {
  409. HeapCallFailed ("HeapCheck failed: Heap is corrupt!", File, Line);
  410. }
  411. LeaveOurCriticalSection (&g_MemAllocCs);
  412. }
  413. #endif
  414. PVOID
  415. ReuseAlloc (
  416. HANDLE Heap,
  417. PVOID OldPtr,
  418. DWORD SizeNeeded
  419. )
  420. {
  421. DWORD CurrentSize;
  422. PVOID Ptr = NULL;
  423. UINT AllocAdjustment = sizeof(DWORD);
  424. //
  425. // HeapSize is a bad thing, so while it may look good, don't
  426. // use it.
  427. //
  428. #ifdef DEBUG
  429. AllocAdjustment += sizeof (DWORD);
  430. #endif
  431. if (!OldPtr) {
  432. Ptr = MemAlloc (Heap, 0, SizeNeeded + AllocAdjustment);
  433. } else {
  434. CurrentSize = *REUSE_SIZE_PTR(OldPtr);
  435. #ifdef DEBUG
  436. if (*REUSE_TAG_PTR(OldPtr) != 0x10a28a70) {
  437. DEBUGMSG ((DBG_WHOOPS, "MemReuse detected corruption!"));
  438. Ptr = MemAlloc (Heap, 0, SizeNeeded + AllocAdjustment);
  439. } else
  440. #endif
  441. if (SizeNeeded > CurrentSize) {
  442. SizeNeeded += 1024 - (SizeNeeded & 1023);
  443. Ptr = MemReAlloc (Heap, 0, REUSE_SIZE_PTR(OldPtr), SizeNeeded + AllocAdjustment);
  444. OldPtr = NULL;
  445. }
  446. }
  447. if (Ptr) {
  448. *((PDWORD) Ptr) = SizeNeeded;
  449. Ptr = (PVOID) ((PBYTE) Ptr + sizeof (DWORD));
  450. #ifdef DEBUG
  451. *REUSE_TAG_PTR(Ptr) = 0x10a28a70;
  452. #endif
  453. }
  454. return Ptr ? Ptr : OldPtr;
  455. }
  456. VOID
  457. ReuseFree (
  458. HANDLE Heap,
  459. PVOID Ptr
  460. )
  461. {
  462. if (Ptr) {
  463. MemFree (Heap, 0, REUSE_SIZE_PTR(Ptr));
  464. }
  465. }
  466. VOID
  467. SetOutOfMemoryParent (
  468. HWND hwnd
  469. )
  470. {
  471. g_OutOfMemoryParentWnd = hwnd;
  472. }
  473. VOID
  474. OutOfMemory_Terminate (
  475. VOID
  476. )
  477. {
  478. MessageBox (
  479. g_OutOfMemoryParentWnd,
  480. g_OutOfMemoryString,
  481. NULL,
  482. MB_OK|MB_ICONHAND|MB_SYSTEMMODAL|MB_SETFOREGROUND|MB_TOPMOST
  483. );
  484. ExitProcess (0);
  485. //
  486. // Not needed, will never get here
  487. //
  488. // TerminateProcess (GetModuleHandle (NULL), 0);
  489. }
  490. VOID
  491. pValidateBlock (
  492. PVOID Block,
  493. SIZE_T Size
  494. )
  495. /*++
  496. Routine Description:
  497. pValidateBlock makes sure Block is non-NULL. If it is NULL, then the user
  498. is given a popup, unless the request size is bogus.
  499. There are two cases for the popup.
  500. - If g_OutOfMemoryParentWnd was set with SetOutOfMemoryParent,
  501. then the user is asked to close other programs, and is given a retry
  502. option.
  503. - If there is no out of memory parent, then the user is told they
  504. need to get more memory.
  505. In either case, Setup is terminated. In GUI mode, Setup will be
  506. stuck and the machine will be unbootable.
  507. Arguments:
  508. Block - Specifies the block to validate.
  509. Size - Specifies the request size
  510. Return Value:
  511. none
  512. --*/
  513. {
  514. LONG rc;
  515. if (!Block && Size < 0x2000000) {
  516. if (g_OutOfMemoryParentWnd) {
  517. rc = MessageBox (
  518. g_OutOfMemoryParentWnd,
  519. g_OutOfMemoryRetry,
  520. NULL,
  521. MB_RETRYCANCEL|MB_ICONHAND|MB_SYSTEMMODAL|MB_SETFOREGROUND|MB_TOPMOST
  522. );
  523. if (rc == IDCANCEL) {
  524. OutOfMemory_Terminate();
  525. }
  526. } else {
  527. OutOfMemory_Terminate();
  528. }
  529. }
  530. }
  531. PVOID
  532. SafeHeapAlloc (
  533. HANDLE Heap,
  534. DWORD Flags,
  535. SIZE_T Size
  536. )
  537. {
  538. PVOID Block;
  539. do {
  540. Block = HeapAlloc (Heap, Flags, Size);
  541. pValidateBlock (Block, Size);
  542. } while (!Block);
  543. return Block;
  544. }
  545. PVOID
  546. SafeHeapReAlloc (
  547. HANDLE Heap,
  548. DWORD Flags,
  549. PVOID OldBlock,
  550. SIZE_T Size
  551. )
  552. {
  553. PVOID Block;
  554. do {
  555. Block = HeapReAlloc (Heap, Flags, OldBlock, Size);
  556. pValidateBlock (Block, Size);
  557. } while (!Block);
  558. return Block;
  559. }
  560. #ifdef DEBUG
  561. VOID
  562. pTrackInsert (
  563. PCSTR File,
  564. DWORD Line,
  565. SIZE_T Size,
  566. PTRACKSTRUCT p
  567. )
  568. {
  569. p->Signature = TRACK_SIGNATURE;
  570. p->File = File;
  571. p->Line = Line;
  572. p->Size = Size;
  573. p->Comment = g_TrackComment ? SafeHeapAlloc (g_hHeap, 0, SizeOfStringA (g_TrackComment)) : NULL;
  574. p->PrevAlloc = NULL;
  575. p->NextAlloc = g_TrackHead;
  576. p->CallerFile = g_TrackFile;
  577. p->CallerLine = g_TrackLine;
  578. if (p->Comment) {
  579. StringCopyA (p->Comment, g_TrackComment);
  580. }
  581. if (g_TrackHead) {
  582. g_TrackHead->PrevAlloc = p;
  583. }
  584. g_TrackHead = p;
  585. }
  586. VOID
  587. pTrackDelete (
  588. PTRACKSTRUCT p
  589. )
  590. {
  591. if (p->Signature != TRACK_SIGNATURE) {
  592. DEBUGMSG ((DBG_WARNING, "A tracking signature is invalid. "
  593. "This suggests memory corruption."));
  594. return;
  595. }
  596. if (p->PrevAlloc) {
  597. p->PrevAlloc->NextAlloc = p->NextAlloc;
  598. } else {
  599. g_TrackHead = p->NextAlloc;
  600. }
  601. if (p->NextAlloc) {
  602. p->NextAlloc->PrevAlloc = p->PrevAlloc;
  603. }
  604. }
  605. VOID
  606. pWriteTrackLog (
  607. VOID
  608. )
  609. {
  610. HANDLE File;
  611. CHAR LineBuf[2048];
  612. PTRACKSTRUCT p;
  613. DWORD DontCare;
  614. DWORD Count;
  615. BOOL BadMem = FALSE;
  616. CHAR TempPath[MAX_TCHAR_PATH];
  617. CHAR memtrackLogPath[] = "?:\\memtrack.log";
  618. if (!g_TrackHead) {
  619. return;
  620. }
  621. GetSystemDirectory(TempPath, MAX_TCHAR_PATH);
  622. memtrackLogPath[0] = TempPath[0];
  623. File = CreateFileA (memtrackLogPath, GENERIC_WRITE, 0, NULL,
  624. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
  625. );
  626. if (File != INVALID_HANDLE_VALUE) {
  627. Count = 0;
  628. __try {
  629. for (p = g_TrackHead ; p ; p = p->NextAlloc) {
  630. Count++;
  631. __try {
  632. if (p->Comment) {
  633. if (p->CallerFile) {
  634. wsprintfA (
  635. LineBuf,
  636. "%s line %u\r\n"
  637. " %s\r\n"
  638. " Caller: %s line %u\r\n"
  639. "\r\n",
  640. p->File,
  641. p->Line,
  642. p->Comment,
  643. p->CallerFile,
  644. p->CallerLine
  645. );
  646. } else {
  647. wsprintfA (LineBuf, "%s line %u\r\n %s\r\n\r\n", p->File, p->Line, p->Comment);
  648. }
  649. } else {
  650. if (p->CallerFile) {
  651. wsprintfA (
  652. LineBuf,
  653. "%s line %u\r\n"
  654. " Caller: %s line %u\r\n"
  655. "\r\n",
  656. p->File,
  657. p->Line,
  658. p->CallerFile,
  659. p->CallerLine
  660. );
  661. } else {
  662. wsprintfA (LineBuf, "(direct alloc) %s line %u\r\n\r\n", p->File, p->Line);
  663. }
  664. }
  665. }
  666. __except (TRUE) {
  667. wsprintfA (LineBuf, "Address %Xh was freed, but not by MemFree!!\r\n", p);
  668. BadMem = TRUE;
  669. }
  670. WriteFile (File, LineBuf, (DWORD)ByteCountA (LineBuf), &DontCare, NULL);
  671. //lint --e(774)
  672. if (BadMem) {
  673. break;
  674. }
  675. }
  676. }
  677. __except (TRUE) {
  678. }
  679. wsprintfA (LineBuf, "\r\n%i item%s allocated but not freed.\r\n", Count, Count == 1 ? "":"s");
  680. WriteFile (File, LineBuf, (DWORD)ByteCountA (LineBuf), &DontCare, NULL);
  681. CloseHandle (File);
  682. }
  683. }
  684. #endif