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.

1040 lines
23 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. dbgmem.c
  5. Abstract:
  6. This module contains memory debug routines for catching memory leaks and memory
  7. overwrites.
  8. Author:
  9. Jim Stewart January 8, 1997
  10. Revision History:
  11. --*/
  12. #include"precomp.h"
  13. #pragma hdrstop
  14. #include<imagehlp.h>
  15. #ifdef DBG
  16. #define ulCheckByteEnd 0x9ABCDEF0
  17. #define cbExtraBytes (sizeof(MEM_TRACKER) + sizeof(DWORD))
  18. #define dwStackLimit 0x00010000 // 64KB for NT
  19. // Protect access to allocated memory chain
  20. CRITICAL_SECTION critsMemory;
  21. BOOL SymbolsInitialized = FALSE;
  22. //
  23. // Head of allocated memory chain
  24. //
  25. LIST_ENTRY MemList;
  26. //
  27. // The type of machine we are on - needed to figure out the call stack
  28. //
  29. DWORD MachineType;
  30. HANDLE OurProcess;
  31. VOID
  32. InitSymbols(
  33. );
  34. BOOL
  35. InitDebugMemory(
  36. )
  37. /*++
  38. Description:
  39. This routine initializes the debug memory functionality.
  40. Arguments:
  41. none
  42. Return Value:
  43. BOOL - pass or fail
  44. --*/
  45. {
  46. BOOL status;
  47. SYSTEM_INFO SysInfo;
  48. __try {
  49. InitializeCriticalSection(&critsMemory);
  50. } __except (EXCEPTION_EXECUTE_HANDLER) {
  51. return FALSE;
  52. }
  53. InitializeListHead( &MemList );
  54. OurProcess = GetCurrentProcess();
  55. GetSystemInfo( &SysInfo );
  56. switch (SysInfo.wProcessorArchitecture) {
  57. default:
  58. case PROCESSOR_ARCHITECTURE_INTEL:
  59. MachineType = IMAGE_FILE_MACHINE_I386;
  60. break;
  61. case PROCESSOR_ARCHITECTURE_MIPS:
  62. //
  63. // note this may not detect R10000 machines correctly
  64. //
  65. MachineType = IMAGE_FILE_MACHINE_R4000;
  66. break;
  67. case PROCESSOR_ARCHITECTURE_ALPHA:
  68. MachineType = IMAGE_FILE_MACHINE_ALPHA;
  69. break;
  70. case PROCESSOR_ARCHITECTURE_PPC:
  71. MachineType = IMAGE_FILE_MACHINE_POWERPC;
  72. break;
  73. }
  74. return( TRUE );
  75. }
  76. VOID
  77. DeInitDebugMemory(
  78. )
  79. /*++
  80. Description:
  81. This routine deinitializes the critical section used by the dbg mem functions.
  82. Arguments:
  83. none
  84. Return Value:
  85. none
  86. --*/
  87. {
  88. DeleteCriticalSection(&critsMemory);
  89. }
  90. VOID
  91. InitSymbols(
  92. )
  93. /*++
  94. Description:
  95. This routine initializes the debug memory functionality.
  96. Arguments:
  97. none
  98. Return Value:
  99. BOOL - pass or fail
  100. --*/
  101. {
  102. BOOL status;
  103. //
  104. // only load the symbols if we are going to track the call stack
  105. //
  106. IF_DEBUG(MEM_CALLSTACK) {
  107. status = SymInitialize( OurProcess,NULL,TRUE );
  108. }
  109. SymbolsInitialized = TRUE;
  110. }
  111. VOID
  112. UpdateCheckBytes(
  113. IN PMEM_TRACKER MemTracker
  114. )
  115. /*++
  116. Description:
  117. This routine adds check bytes at the end of allocatedmemory. These check bytes are used to check
  118. for memory overwrites. Also a check sum in the MEM_TRACKER structure is also set here.
  119. Arguments:
  120. MemTracker newly allocated memory block
  121. Return Value:
  122. none
  123. --*/
  124. {
  125. *((DWORD*)(((PUCHAR)MemTracker) + MemTracker->nSize + sizeof(MEM_TRACKER))) = ulCheckByteEnd;
  126. MemTracker->ulCheckSum = ulCheckByteEnd +
  127. PtrToUlong(MemTracker->szFile) +
  128. MemTracker->nLine +
  129. MemTracker->nSize +
  130. PtrToUlong(MemTracker->Linkage.Blink) +
  131. PtrToUlong(MemTracker->Linkage.Flink);
  132. }
  133. BOOL
  134. FCheckCheckBytes(
  135. IN PMEM_TRACKER MemTracker
  136. )
  137. /*++
  138. Description:
  139. This routine checks the check sum in the MEM_TRACKER structure, called before freeing the allocated
  140. memory.
  141. Arguments:
  142. MemTracker memory block whose check sum needs to be validated
  143. Return Value:
  144. TRUE if check sum is correct
  145. FALSE otherwise
  146. --*/
  147. {
  148. DWORD ul;
  149. ul = *((DWORD*)(((PUCHAR)MemTracker)+MemTracker->nSize+sizeof(MEM_TRACKER))) +
  150. PtrToUlong(MemTracker->szFile) +
  151. MemTracker->nLine +
  152. MemTracker->nSize +
  153. PtrToUlong(MemTracker->Linkage.Blink) +
  154. PtrToUlong(MemTracker->Linkage.Flink);
  155. if (ul != MemTracker->ulCheckSum) {
  156. WSPRINT(( "Memory overwrite on location 0x%08lx\n",
  157. PtrToUlong(MemTracker+sizeof(MEM_TRACKER)) ));
  158. return FALSE;
  159. }
  160. return TRUE;
  161. }
  162. BOOL
  163. FCheckAllocatedMemory()
  164. /*++
  165. Description:
  166. This routine walks the allocated memory list and checks for validity of check sum and check
  167. bytes.
  168. Arguments:
  169. none
  170. Return Value:
  171. TRUE if all the allocated memory pass the above two checks.
  172. FALSE otherwise
  173. --*/
  174. {
  175. PMEM_TRACKER MemTracker;
  176. BOOL check = TRUE;
  177. PLIST_ENTRY Entry;
  178. IF_DEBUG(CHKSUM_ALLMEM) {
  179. EnterCriticalSection(&critsMemory);
  180. for (Entry = MemList.Flink; Entry != &MemList; Entry = Entry->Flink ) {
  181. MemTracker = CONTAINING_RECORD( Entry,MEM_TRACKER,Linkage );
  182. if (!FCheckCheckBytes(MemTracker)) {
  183. check = FALSE;
  184. }
  185. }
  186. LeaveCriticalSection(&critsMemory);
  187. }
  188. return check;
  189. }
  190. VOID
  191. AddMemTracker(
  192. IN PMEM_TRACKER MemTracker
  193. )
  194. /*++
  195. Description:
  196. Adds the supplied MEM_TRACKER at the tail of the doubly linked allocated memory list and
  197. set the check sum also.
  198. Arguments:
  199. MemTracker MEM_TRACKER * to be added to the list
  200. Return Value:
  201. none
  202. --*/
  203. {
  204. PMEM_TRACKER Tracker;
  205. ASSERT(MemTracker);
  206. InsertTailList( &MemList,&MemTracker->Linkage );
  207. UpdateCheckBytes( MemTracker );
  208. FCheckCheckBytes( MemTracker );
  209. //
  210. // if there are other blocks in the list then change their check sum
  211. // since we have just changed their Flink to point to us
  212. //
  213. if (MemTracker->Linkage.Blink != &MemList) {
  214. Tracker = CONTAINING_RECORD( MemTracker->Linkage.Blink,MEM_TRACKER,Linkage );
  215. UpdateCheckBytes( Tracker );
  216. FCheckCheckBytes( Tracker );
  217. }
  218. }
  219. VOID
  220. RemoveMemTracker(
  221. IN PMEM_TRACKER MemTracker
  222. )
  223. /*++
  224. Description:
  225. Removes the supplied MEM_TRACKER * from the list of allocated memory. Also checks
  226. for memory overwites and updated the check sum for the entries before and
  227. after the entry being removed
  228. Arguments:
  229. MemTracker MEM_TRACKER to remove from the list
  230. Return Value:
  231. none
  232. --*/
  233. {
  234. ASSERT(MemTracker);
  235. //
  236. // Validate the check sum before
  237. // removing from the list
  238. //
  239. FCheckCheckBytes(MemTracker);
  240. //
  241. // Remove MemTracker from the list
  242. //
  243. RemoveEntryList( &MemTracker->Linkage );
  244. //
  245. // Since the check sum is based on next and
  246. // prev pointers, need to update the check
  247. // sum for prev entry
  248. //
  249. if (MemTracker->Linkage.Blink != &MemList) {
  250. UpdateCheckBytes((MEM_TRACKER*)MemTracker->Linkage.Blink);
  251. FCheckCheckBytes((MEM_TRACKER*)MemTracker->Linkage.Blink);
  252. }
  253. if (MemTracker->Linkage.Flink != &MemList) {
  254. UpdateCheckBytes((MEM_TRACKER*)MemTracker->Linkage.Flink);
  255. FCheckCheckBytes((MEM_TRACKER*)MemTracker->Linkage.Flink);
  256. }
  257. }
  258. BOOL
  259. ReadMem(
  260. IN HANDLE hProcess,
  261. IN ULONG_PTR BaseAddr,
  262. IN PVOID Buffer,
  263. IN DWORD Size,
  264. IN PDWORD NumBytes )
  265. /*++
  266. Description:
  267. This is a callback routine that StackWalk uses - it just calls teh system ReadProcessMemory
  268. routine with this process's handle
  269. Arguments:
  270. Return Value:
  271. none
  272. --*/
  273. {
  274. BOOL status;
  275. SIZE_T RealNumBytes;
  276. status = ReadProcessMemory( GetCurrentProcess(),
  277. (LPCVOID)BaseAddr,
  278. Buffer,
  279. Size,
  280. &RealNumBytes );
  281. *NumBytes = (DWORD)RealNumBytes;
  282. return( status );
  283. }
  284. VOID
  285. GetCallStack(
  286. IN PCALLER_SYM Caller,
  287. IN int Skip,
  288. IN int cFind
  289. )
  290. /*++
  291. Description:
  292. This routine walks te stack to find the return address of caller. The number of callers
  293. and the number of callers on top to be skipped can be specified.
  294. Arguments:
  295. pdwCaller array of DWORD to return callers
  296. return addresses
  297. Skip no. of callers to skip
  298. cFInd no. of callers to find
  299. Return Value:
  300. none
  301. --*/
  302. {
  303. BOOL status;
  304. CONTEXT ContextRecord;
  305. PUCHAR Buffer[sizeof(IMAGEHLP_SYMBOL)-1 + MAX_FUNCTION_INFO_SIZE];
  306. PIMAGEHLP_SYMBOL Symbol = (PIMAGEHLP_SYMBOL)Buffer;
  307. STACKFRAME StackFrame;
  308. INT i;
  309. DWORD Count;
  310. memset(Caller, 0, cFind * sizeof(CALLER_SYM));
  311. ZeroMemory( &ContextRecord,sizeof( CONTEXT ) );
  312. ContextRecord.ContextFlags = CONTEXT_CONTROL;
  313. status = GetThreadContext( GetCurrentThread(),&ContextRecord );
  314. ZeroMemory( &StackFrame,sizeof(STACKFRAME) );
  315. StackFrame.AddrPC.Segment = 0;
  316. StackFrame.AddrPC.Mode = AddrModeFlat;
  317. #ifdef _M_IX86
  318. StackFrame.AddrFrame.Offset = ContextRecord.Ebp;
  319. StackFrame.AddrFrame.Mode = AddrModeFlat;
  320. StackFrame.AddrStack.Offset = ContextRecord.Esp;
  321. StackFrame.AddrStack.Mode = AddrModeFlat;
  322. StackFrame.AddrPC.Offset = (DWORD)ContextRecord.Eip;
  323. #elif defined(_M_MRX000)
  324. StackFrame.AddrPC.Offset = (DWORD)ContextRecord.Fir;
  325. #elif defined(_M_ALPHA)
  326. StackFrame.AddrPC.Offset = (DWORD)ContextRecord.Fir;
  327. #elif defined(_M_PPC)
  328. StackFrame.AddrPC.Offset = (DWORD)ContextRecord.Iar;
  329. #endif
  330. Count = 0;
  331. for (i=0;i<cFind+Skip ;i++ ) {
  332. status = StackWalk( MachineType,
  333. OurProcess,
  334. GetCurrentThread(),
  335. &StackFrame,
  336. (PVOID)&ContextRecord,
  337. ReadMem,
  338. SymFunctionTableAccess,
  339. SymGetModuleBase,
  340. NULL );
  341. if (status && i >= Skip) {
  342. DWORD_PTR Displacement;
  343. ZeroMemory( Symbol,sizeof(IMAGEHLP_SYMBOL)-1 + MAX_FUNCTION_INFO_SIZE );
  344. Symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  345. Symbol->Address = StackFrame.AddrPC.Offset;
  346. Symbol->MaxNameLength = MAX_FUNCTION_INFO_SIZE-1;
  347. Symbol->Flags = SYMF_OMAP_GENERATED;
  348. status = SymGetSymFromAddr( OurProcess,
  349. StackFrame.AddrPC.Offset,
  350. &Displacement,
  351. Symbol );
  352. //
  353. // save the name of the function and the displacement into it for later printing
  354. //
  355. if (status) {
  356. strcpy( Caller[Count].Buff,Symbol->Name );
  357. Caller[Count].Displacement = Displacement;
  358. }
  359. Count++;
  360. }
  361. }
  362. }
  363. PVOID
  364. AllocMemory(
  365. IN DWORD nSize,
  366. IN BOOL Calloc,
  367. IN PSZ szFileName,
  368. IN DWORD nLine
  369. )
  370. /*++
  371. Description:
  372. This routine is the memory allocator (like malloc) for DBG builds. This routine allocated
  373. more memory than requested by the caller. In this extra space this routine save info to
  374. track memory leaks, overwrite, callers etc. All the info is stored in a MEM_TRACKER structure
  375. which preceed the buffer to be returned.
  376. Arguments:
  377. nSize size of the required buffer.
  378. Calloc if true then call Calloc ( which initializes memory to zero )
  379. szFileName name of the file which contains
  380. the routine asking for memory.
  381. nLine line number in the above file
  382. which has the call to PvAlloc.
  383. Return Value:
  384. address of the allocated buffer.
  385. --*/
  386. {
  387. PVOID pvRet;
  388. PMEM_TRACKER MemTracker;
  389. static DWORD ulAllocs = 0;
  390. PUCHAR FileName;
  391. if (!SymbolsInitialized){
  392. InitSymbols();
  393. }
  394. EnterCriticalSection(&critsMemory);
  395. ++ulAllocs;
  396. //
  397. // Check entire allocated memory for overwite
  398. //
  399. if ( !FCheckAllocatedMemory() ) {
  400. WSPRINT(("Memory Overwrite detected in AllocMemory\n" ));
  401. ASSERT(0);
  402. }
  403. //
  404. // Size of the allocated memory is always
  405. // a multiple of sizeof(DWORD)
  406. //
  407. nSize = ((nSize +3) /4) * 4;
  408. //
  409. // shorten file name to just be the file name and not the path too
  410. //
  411. FileName = strrchr( szFileName,'\\' );
  412. if (!FileName) {
  413. FileName = szFileName;
  414. } else {
  415. FileName++; // skip /
  416. }
  417. //
  418. // Allocate extra for MEM_TRACKER and guard byte at end
  419. //
  420. if (!Calloc) {
  421. pvRet = malloc( nSize + cbExtraBytes );
  422. } else {
  423. //
  424. // this routine will initialize the memory to zero
  425. //
  426. pvRet = calloc( 1,(nSize + cbExtraBytes) );
  427. }
  428. if (!pvRet) {
  429. IF_DEBUG(ERRORS) {
  430. WSPRINT(( "Memory alloc failed size=%li, %s line %li\n",
  431. nSize,
  432. FileName,
  433. nLine ));
  434. }
  435. LeaveCriticalSection(&critsMemory);
  436. return NULL;
  437. }
  438. //
  439. // Fill in new alloc with 0xFA.
  440. //
  441. if (!Calloc) {
  442. memset(pvRet, 0xFA, nSize+cbExtraBytes);
  443. }
  444. //
  445. // Save all the debug info needed in MEM_TRACKER
  446. //
  447. MemTracker = pvRet;
  448. MemTracker->szFile = FileName;
  449. MemTracker->nLine = nLine;
  450. MemTracker->nSize = nSize;
  451. MemTracker->ulAllocNum = ulAllocs;
  452. //
  453. // only save the call stack info if it is turned on
  454. //
  455. IF_DEBUG(MEM_CALLSTACK) {
  456. GetCallStack( MemTracker->Callers,
  457. 3,
  458. NCALLERS);
  459. }
  460. //
  461. // Add to the list
  462. //
  463. AddMemTracker(MemTracker);
  464. LeaveCriticalSection(&critsMemory);
  465. IF_DEBUG(MEMORY_ALLOC) {
  466. WSPRINT(( "Memory alloc (0x%08lX) size=%li, %s line %li\n",
  467. PtrToUlong(pvRet)+sizeof(MEM_TRACKER),
  468. nSize,
  469. FileName,
  470. nLine ));
  471. }
  472. //
  473. // Return the address following the MEM_TRACKER as
  474. // address of the buffer allocated.
  475. //
  476. return (PVOID)((PUCHAR)pvRet+sizeof(MEM_TRACKER));
  477. }
  478. PVOID
  479. ReAllocMemory(
  480. IN PVOID pvOld,
  481. IN DWORD nSizeNew,
  482. IN PSZ szFileName,
  483. IN DWORD nLine
  484. )
  485. /*++
  486. Description:
  487. This routine is the DBG version of realloc memory allocator function. This routine
  488. works just like PvAlloc function.
  489. Arguments:
  490. pvOld address of the buffer whose size
  491. needs to be changed.
  492. nSizeNew new size of the required buffer.
  493. szFileName name of the file which contains
  494. the routine asking for memory.
  495. nLine line number in the above file
  496. which has the call to PvAlloc.
  497. Return Value:
  498. address of the buffer with the new size.
  499. --*/
  500. {
  501. PVOID pvRet;
  502. PMEM_TRACKER MemTracker;
  503. //
  504. // Check the entire allocated memory for
  505. // overwrites.
  506. //
  507. if ( !FCheckAllocatedMemory() ) {
  508. WSPRINT(("Memory Overwrite detected in ReAllocMemory\n" ));
  509. ASSERT(0);
  510. }
  511. ASSERT(pvOld);
  512. //
  513. // Size of the memory allocated is always
  514. // a multiple of sizeof(DWORD)
  515. //
  516. nSizeNew = ((nSizeNew + 3)/4) *4;
  517. //
  518. // Extra space for MEM_TRACKER and Guard bytes
  519. //
  520. pvRet = realloc(pvOld, nSizeNew+cbExtraBytes);
  521. if (!pvRet) {
  522. IF_DEBUG(MEMORY_ALLOC) {
  523. WSPRINT(( "Memory realloc failed (0x%08lX) size=%li, %s line %li\n",
  524. PtrToUlong(pvOld) + sizeof(MEM_TRACKER),
  525. nSizeNew,
  526. szFileName,
  527. nLine ));
  528. }
  529. } else {
  530. IF_DEBUG(MEMORY_ALLOC) {
  531. WSPRINT(( "Memory realloc succeeded (0x%08lX) size=%li, %s line %li\n",
  532. PtrToUlong(pvOld) + sizeof(MEM_TRACKER),
  533. PtrToUlong(pvRet)+sizeof(MEM_TRACKER),
  534. nSizeNew,
  535. szFileName,
  536. nLine ));
  537. }
  538. MemTracker = (PMEM_TRACKER)pvRet;
  539. if (nSizeNew > (DWORD)MemTracker->nSize) {
  540. //
  541. // Fill in extra alloc with 0xEA.
  542. //
  543. memset((PUCHAR)pvRet+sizeof(MEM_TRACKER)+MemTracker->nSize, 0xEA, nSizeNew - MemTracker->nSize);
  544. }
  545. MemTracker = pvRet;
  546. MemTracker->szFile = szFileName;
  547. MemTracker->nLine = nLine;
  548. MemTracker->nSize = nSizeNew;
  549. }
  550. //
  551. // Add the new buffer to the list and update check sum
  552. //
  553. AddMemTracker(MemTracker);
  554. LeaveCriticalSection(&critsMemory);
  555. if (pvRet)
  556. return (PVOID)((PUCHAR)pvRet+sizeof(MEM_TRACKER));
  557. else
  558. return NULL;
  559. }
  560. VOID
  561. FreeMemory(
  562. IN PVOID pv,
  563. IN PSZ szFileName,
  564. IN DWORD nLine
  565. )
  566. /*++
  567. Description:
  568. This is the DBG version of free function. This routine checks for memory overwrites in the
  569. block of memory being freed before removing from the list.
  570. Arguments:
  571. pv address of the buffer to be freed
  572. szFileName name of the file from which this
  573. block of memory is being freed.
  574. nLine line number in the above file
  575. which has the call to FreePvFn.
  576. Return Value:
  577. none
  578. --*/
  579. {
  580. PMEM_TRACKER MemTracker;
  581. ASSERT(pv);
  582. if (NULL == pv)
  583. return;
  584. EnterCriticalSection(&critsMemory);
  585. MemTracker = (PMEM_TRACKER)((PUCHAR)pv-sizeof(MEM_TRACKER));
  586. //
  587. // Check for memory overwrites
  588. //
  589. if (!FCheckCheckBytes(MemTracker)) {
  590. WSPRINT(( "Memory Overwrite detected when freeing memory\n" ));
  591. ASSERT(0);
  592. }
  593. if ( !FCheckAllocatedMemory() ){
  594. WSPRINT(("Memory Overwrite - detected when checking allocated mem when freeing a block\n" ));
  595. ASSERT(0);
  596. }
  597. IF_DEBUG(MEMORY_FREE) {
  598. PUCHAR FileName;
  599. //
  600. // shorten file name to just be the file name and not the path too
  601. //
  602. FileName = strrchr( szFileName,'\\' );
  603. if (!FileName) {
  604. FileName = szFileName;
  605. } else {
  606. FileName++; // skip /
  607. }
  608. WSPRINT(( "Memory freed (0x%08lX) size=%li, %s line %li\n",
  609. PtrToUlong(pv),
  610. MemTracker->nSize,
  611. FileName,
  612. nLine ));
  613. }
  614. //
  615. // Remove from the list
  616. //
  617. RemoveMemTracker(MemTracker);
  618. //
  619. // Fill in freed alloc with 0xCC.
  620. //
  621. memset(MemTracker, 0xCC, MemTracker->nSize+cbExtraBytes);
  622. free( MemTracker );
  623. LeaveCriticalSection(&critsMemory);
  624. }
  625. BOOL
  626. DumpAllocatedMemory()
  627. /*++
  628. Description:
  629. This routine is called during shutdown to dump out any unfreed memory blocks.
  630. Arguments:
  631. none
  632. Return Value:
  633. TRUE if there are any unfreed memory blocks.
  634. FALSE if all the allocated memory has been freed.
  635. --*/
  636. {
  637. BOOL status;
  638. PMEM_TRACKER MemTracker;
  639. DWORD ulNumBlocks = 0;
  640. DWORD ulTotalMemory = 0;
  641. PLIST_ENTRY Entry;
  642. //
  643. // If the head of the chain is NULL,
  644. // all memory has been freed.
  645. //
  646. IF_DEBUG(DUMP_MEM) {
  647. EnterCriticalSection(&critsMemory);
  648. WSPRINT(("\n\n*** Start dumping unfreed memory ***\n\n",0 ));
  649. for (Entry = MemList.Flink; Entry != &MemList; Entry = Entry->Flink) {
  650. INT i;
  651. MemTracker = CONTAINING_RECORD( Entry,MEM_TRACKER,Linkage );
  652. ulNumBlocks++;
  653. ulTotalMemory += MemTracker->nSize;
  654. WSPRINT(( "(0x%08lX) size=%li, %s line %li alloc# 0x%lx\n",
  655. PtrToUlong(MemTracker)+sizeof(MEM_TRACKER),
  656. MemTracker->nSize,
  657. MemTracker->szFile,
  658. MemTracker->nLine,
  659. MemTracker->ulAllocNum ));
  660. //
  661. // dump the call stack if that debugging is on
  662. //
  663. IF_DEBUG(MEM_CALLSTACK) {
  664. for (i = 0; i < NCALLERS && MemTracker->Callers[i].Buff[0] != 0; i++) {
  665. WSPRINT(( "%d %s + 0x%X \n",i,MemTracker->Callers[i].Buff,MemTracker->Callers[i].Displacement ));
  666. }
  667. }
  668. FCheckCheckBytes( MemTracker );
  669. }
  670. if (ulNumBlocks > 0) {
  671. WSPRINT(( "%li blocks allocated, and %li bytes\n",
  672. ulNumBlocks,
  673. ulTotalMemory ));
  674. status = TRUE;
  675. } else {
  676. status = FALSE;
  677. }
  678. WSPRINT(( "\n\n*** Finished dumping memory ***\n\n",0 ));
  679. LeaveCriticalSection(&critsMemory);
  680. }
  681. return status;
  682. }
  683. BOOL
  684. SearchAllocatedMemory(
  685. IN PSZ szFile,
  686. IN DWORD nLine
  687. )
  688. /*++
  689. Description:
  690. This routine dumps details about memory allocated by a given line of code in a given file.
  691. Arguments:
  692. szFile name of the file
  693. nLine line number of code whose memory allocationto be displayed
  694. Return Value:
  695. TRUE if there was atleast one memory block allocated by the given line number
  696. in the given file.
  697. FALE otherwise.
  698. --*/
  699. {
  700. PMEM_TRACKER MemTracker;
  701. BOOL fFound = FALSE;
  702. PLIST_ENTRY Entry;
  703. EnterCriticalSection(&critsMemory);
  704. WSPRINT(( "Searching memory\n", 0 ));
  705. for (Entry = MemList.Flink; Entry != &MemList; Entry = Entry->Flink ) {
  706. MemTracker = CONTAINING_RECORD( Entry,MEM_TRACKER,Linkage );
  707. //
  708. // Look for a match on filename and line number
  709. //
  710. if ( strcmp(MemTracker->szFile, szFile) == 0 && MemTracker->nLine == nLine ) {
  711. ASSERT(FALSE);
  712. WSPRINT(( "(0x%08lX) size=%li, %s line %li alloc# 0x%lx\n",
  713. PtrToUlong(MemTracker)+sizeof(MEM_TRACKER),
  714. MemTracker->nSize,
  715. MemTracker->szFile,
  716. MemTracker->nLine,
  717. MemTracker->ulAllocNum));
  718. fFound = TRUE;
  719. break;
  720. }
  721. }
  722. LeaveCriticalSection(&critsMemory);
  723. WSPRINT(( "Finished searching memory\n",0 ));
  724. return fFound;
  725. }
  726. #endif // DBG