home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 18.ddi / MFC / SRC / AFXMEM.CP_ / AFXMEM.CP
Encoding:
Text File  |  1993-02-08  |  20.7 KB  |  783 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library. 
  2. // Copyright (C) 1992 Microsoft Corporation 
  3. // All rights reserved. 
  4. //  
  5. // This source code is only intended as a supplement to the 
  6. // Microsoft Foundation Classes Reference and Microsoft 
  7. // QuickHelp and/or WinHelp documentation provided with the library. 
  8. // See these sources for detailed information regarding the 
  9. // Microsoft Foundation Classes product. 
  10.  
  11.  
  12. #include "stdafx.h"
  13. #include <limits.h>
  14. #define SIZE_T_MAX  UINT_MAX
  15.  
  16. #ifdef AFX_CORE1_SEG
  17. #pragma code_seg(AFX_CORE1_SEG)
  18. #endif
  19.  
  20.  
  21. #ifdef _DEBUG
  22. #undef THIS_FILE
  23. static char BASED_CODE THIS_FILE[] = __FILE__;
  24. #endif
  25.  
  26. /////////////////////////////////////////////////////////////////////////////
  27.  
  28. #ifdef _DEBUG       // most of this file is for debugging
  29.  
  30. // forward
  31. static void* NEAR PASCAL AllocMemoryDebug(size_t nSize, BOOL bIsObject, 
  32.     LPCSTR lpszFileName, int nLine);
  33. static void NEAR PASCAL FreeMemoryDebug(void* pbData, BOOL bIsObject);
  34.  
  35. /////////////////////////////////////////////////////////////////////////////
  36. // test allocation routines
  37.  
  38. extern "C" int NEAR afxMemDF = allocMemDF;
  39.  
  40. void* operator new(size_t nSize)
  41. {
  42.     // memory corrupt before global new
  43.     if (afxMemDF & checkAlwaysMemDF)
  44.         ASSERT(AfxCheckMemory()); 
  45.  
  46.     void* p = AllocMemoryDebug(nSize, FALSE, NULL, 0);
  47.  
  48.     if (p == NULL)
  49.     {
  50.         TRACE1("::operator new(%u) failed - throwing exception\n", nSize);
  51.         AfxThrowMemoryException();
  52.     }
  53.     
  54.     return p;
  55. }
  56.  
  57. void* operator new(size_t nSize, LPCSTR lpszFileName, int nLine)
  58. {
  59.     // memory corrupt before global new
  60.     if (afxMemDF & checkAlwaysMemDF)
  61.         ASSERT(AfxCheckMemory()); 
  62.  
  63.     void* p = AllocMemoryDebug(nSize, FALSE, lpszFileName, nLine);
  64.     
  65.     if (p == NULL)
  66.     {
  67.         TRACE1("::operator new(%u) failed - throwing exception\n", nSize);
  68.         AfxThrowMemoryException();
  69.     }
  70.  
  71.     return p;
  72. }
  73.  
  74. void operator delete(void* pbData)
  75. {
  76.     // memory corrupt before global delete
  77.     if (afxMemDF & checkAlwaysMemDF)
  78.         ASSERT(AfxCheckMemory()); 
  79.  
  80.     FreeMemoryDebug(pbData, FALSE);
  81. }
  82.  
  83. void* CObject::operator new(size_t nSize)
  84. {
  85.     // memory corrupt before global new
  86.     if (afxMemDF & checkAlwaysMemDF)
  87.         ASSERT(AfxCheckMemory()); 
  88.  
  89.     void* p = AllocMemoryDebug(nSize, TRUE, NULL, 0);
  90.     
  91.     if (p == NULL)
  92.     {
  93.         TRACE1("CObject::operator new(%u) failed - throwing exception\n", nSize);
  94.         AfxThrowMemoryException();
  95.     }
  96.  
  97.     return p;
  98. }
  99.  
  100. void* 
  101. CObject::operator new(size_t nSize, LPCSTR lpszFileName, int nLine)
  102. {
  103.     // memory corrupt before 'CObject::new'
  104.     if (afxMemDF & checkAlwaysMemDF)
  105.         ASSERT(AfxCheckMemory()); 
  106.  
  107.     void* p = AllocMemoryDebug(nSize, TRUE, lpszFileName, nLine);
  108.     
  109.     if (p == NULL)
  110.     {
  111.         TRACE1("CObject::operator new(%u) failed - throwing exception\n", nSize);
  112.         AfxThrowMemoryException();
  113.     }
  114.  
  115.     return p;
  116. }
  117.  
  118. void CObject::operator delete(void* pbData)
  119. {
  120.     // memory corrupt before 'CObject::delete'
  121.     if (afxMemDF & checkAlwaysMemDF)
  122.         ASSERT(AfxCheckMemory()); 
  123.  
  124.     FreeMemoryDebug(pbData, TRUE);
  125. }
  126.  
  127. /////////////////////////////////////////////////////////////////////////////
  128. // allocation failure hook, tracking turn on
  129.  
  130. #ifndef _AFXDLL
  131. static BOOL NEAR bTrackingOn = TRUE;
  132. #else
  133. #define bTrackingOn (_AfxGetAppDebug()->bMemoryTracking)
  134. #endif
  135.  
  136. BOOL AFXAPI _AfxDefaultAllocHook(size_t, BOOL, LONG)
  137.     { return TRUE; }
  138.  
  139. static AFX_ALLOC_HOOK NEAR pfnAllocHook = _AfxDefaultAllocHook;
  140.  
  141. AFX_ALLOC_HOOK AFXAPI AfxSetAllocHook(AFX_ALLOC_HOOK pfnNewHook)
  142. {
  143.     AFX_ALLOC_HOOK pfnOldHook = pfnAllocHook;
  144.     pfnAllocHook = pfnNewHook;
  145.     return pfnOldHook;
  146. }
  147.  
  148. #ifndef _AFXDLL     // In DLL version, exported by MFC200D.DLL (see dllinit.cpp)
  149. BOOL AFXAPI AfxEnableMemoryTracking(BOOL bTrack)
  150. {
  151.     BOOL bOldTrackingOn = bTrackingOn;
  152.     bTrackingOn = bTrack;
  153.     return bOldTrackingOn;
  154. }
  155. #endif //!_AFXDLL
  156.  
  157. /////////////////////////////////////////////////////////////////////////////
  158. // stop on a specific memory request
  159.  
  160. #ifndef _PORTABLE
  161. static LONG NEAR lStopRequest = 0;
  162. static AFX_ALLOC_HOOK NEAR pfnOldStopHook = NULL;
  163.  
  164. #pragma optimize("qgel", off) // assembler cannot be globally optimized
  165. extern "C" void AFXAPI AfxStop()
  166. {
  167.     // set a breakpoint on this routine from debugger
  168.     TRACE0("AfxStop() stopping under the debugger\n");
  169.     _asm { int 3 };
  170.     TRACE0("AfxStop() continues\n");
  171. }
  172. #pragma optimize("", on)
  173.  
  174. BOOL AFXAPI _AfxTestAllocStop(size_t nSize, BOOL bIsObject, 
  175.         LONG lRequest)
  176. {
  177.     if (lRequest == lStopRequest)
  178.     {
  179.         TRACE1("Allocating block # %ld\n", lRequest);
  180.         AfxStop();
  181.     }
  182.  
  183.     // otherwise just pass on to other hook
  184.     return (*pfnOldStopHook)(nSize, bIsObject, lRequest);
  185. }
  186.  
  187. // Obsolete API
  188. void AFXAPI AfxSetAllocStop(LONG lRequestNumber)
  189. {
  190.     if (pfnOldStopHook == NULL)
  191.         pfnOldStopHook = AfxSetAllocHook(_AfxTestAllocStop);
  192.  
  193.     lStopRequest = lRequestNumber;
  194. }
  195. #endif
  196.  
  197. /////////////////////////////////////////////////////////////////////////////
  198. // AFX Memory Management diagnostics - malloc-like
  199. //
  200.  
  201. // we keep statistics on what memory is/was used
  202. static LONG NEAR lTotalAlloc;// total bytes of memory allocated 
  203. static LONG NEAR lCurAlloc; // current bytes of memory allocated 
  204. static LONG NEAR lMaxAlloc; // maximum bytes of memory allocated at any one time 
  205.  
  206. // we keep a request count to use in replaying memory consumption
  207. static LONG NEAR lRequestLast = 0;
  208. #define lNotTracked 0       // if not tracked 
  209.  
  210. // for diagnostic purpose, blocks are allocated with extra information and
  211. //  stored in a doubly-linked list.  This makes all blocks registered with
  212. //  how big they are, when they were allocated and what they are used for.
  213.  
  214. static struct CBlockHeader* NEAR pFirstBlock = NULL;    // add in reverse order
  215.  
  216. //  A no-mans-land area is allocated before and after the actual data:
  217. //      ---------
  218. //          start of CBlockHeader pFirstBlocker (linkage and statistical info)
  219. //          no man's land before actual data
  220. //          app pointer-> actual data
  221. //          no man's land after actual data
  222. //      ---------
  223.  
  224. #define nNoMansLandSize     4       // # of bytes 
  225.  
  226. // The following values are non-zero, contant, odd, large, and atypical
  227. //      Non-zero values help find bugs assuming zero filled data.
  228. //      Constant values are good so that memory filling is deterministic
  229. //          (to help make bugs reproducable).  Of course it is bad if
  230. //          the contant filling of weird values masks a bug.
  231. //      Mathematically odd numbers are good for finding bugs assuming a cleared
  232. //          lower bit, as well as useful for trapping on the Mac.
  233. //      Large numbers (byte values at least) are less typical, and are good
  234. //          at finding bad addresses.
  235. //      Atypical values (i.e. not too often) are good since they typically
  236. //          cause early detection in code.
  237. //      For the case of no-man's land and free blocks, if you store to any
  238. //          of these locations, the memory integrity checker will detect it.
  239.  
  240. #define bNoMansLandFill     0xFD    // fill no-man's land with this 
  241. #define bDeadLandFill       0xDD    // fill free objects with this 
  242. #define bCleanLandFill      0xCD    // fill new objects with this 
  243.  
  244. // three uses for registered blocks
  245. static char BASED_CODE szFree[] = "Free";
  246. static char BASED_CODE szObject[] = "Object";
  247. static char BASED_CODE szNonObject[] = "Non-Object";
  248. static char BASED_CODE szDamage[] = "Damage";
  249. static LPCSTR BASED_CODE blockUseName[CMemoryState::nBlockUseMax] =
  250.     { szFree, szObject, szNonObject };
  251.  
  252. struct CBlockHeader 
  253. {
  254.     struct CBlockHeader* pBlockHeaderNext;
  255.     struct CBlockHeader* pBlockHeaderPrev;
  256.     LPCSTR              lpszFileName;
  257.     int                 nLine;
  258.     size_t              nDataSize;
  259.     enum CMemoryState::blockUsage use;
  260.     LONG                lRequest;
  261.     BYTE                gap[nNoMansLandSize];
  262.     // followed by:
  263.     //  BYTE            data[nDataSize];
  264.     //  BYTE            anotherGap[nNoMansLandSize];
  265.     BYTE* pbData()
  266.         { return (BYTE*) (this + 1); }
  267. };
  268.  
  269. static void* NEAR PASCAL
  270. AllocMemoryDebug(size_t nSize, BOOL bIsObject, LPCSTR lpszFileName, int nLine)
  271. // Allocate a memory block of the specific nSize with extra diagnostic
  272. //      support (padding on either nSize of block + linkage)
  273. // Mark it either as object (stores a non-primitive object) or just bits
  274. {
  275.     ASSERT(nSize > 0);
  276.  
  277.     LONG    lRequest;
  278.     lRequest = bTrackingOn ? ++lRequestLast : lNotTracked;
  279.  
  280.     // forced failure
  281.     if (!(*pfnAllocHook)(nSize, bIsObject, lRequest))
  282.     {
  283.         TRACE2("diagnostic memory allocation failure at file %Fs line %d\n", 
  284.             lpszFileName, nLine);
  285.         return NULL;
  286.     }
  287.  
  288.     if (!(afxMemDF & allocMemDF))
  289.         return malloc(nSize);
  290.  
  291.     // Diagnostic memory allocation from this point on
  292.     if (nSize > (size_t)SIZE_T_MAX - nNoMansLandSize - sizeof(CBlockHeader))
  293.     {
  294.         TRACE1("Error: memory allocation: tried to allocate %u bytes\n", nSize);
  295.         TRACE0("  object too large or negative size\n");
  296.         AfxThrowMemoryException();
  297.     }
  298.  
  299.     // keep track of total amount of memory allocated
  300.     lTotalAlloc += nSize;
  301.     lCurAlloc += nSize;
  302.  
  303.     if (lCurAlloc > lMaxAlloc)
  304.         lMaxAlloc = lCurAlloc;
  305.             
  306.     struct CBlockHeader* p = (struct CBlockHeader*)
  307.        malloc(sizeof(CBlockHeader) + nSize + nNoMansLandSize);
  308.  
  309.     if (p == NULL)
  310.         return NULL;
  311.  
  312.     if (pFirstBlock)
  313.         pFirstBlock->pBlockHeaderPrev = p;
  314.  
  315.     p->pBlockHeaderNext = pFirstBlock;
  316.     p->pBlockHeaderPrev = NULL;
  317.     p->lpszFileName = lpszFileName;
  318.     p->nLine = nLine;
  319.     p->nDataSize = nSize;
  320.     p->use = bIsObject ? CMemoryState::objectBlock : CMemoryState::bitBlock;
  321.     p->lRequest = lRequest;
  322.  
  323.     // fill in gap before and after real block 
  324.     memset(p->gap, bNoMansLandFill, nNoMansLandSize);
  325.     memset(p->pbData() + nSize, bNoMansLandFill, nNoMansLandSize);
  326.  
  327.     // fill data with silly value (but non-zero) 
  328.     memset(p->pbData(), bCleanLandFill, nSize);
  329.  
  330.     // link blocks together
  331.     pFirstBlock = p;
  332.     return (void*)p->pbData();
  333. }
  334.  
  335.  
  336. // debugging free
  337. static void NEAR PASCAL
  338. FreeMemoryDebug(void* pbData, BOOL bIsObject)
  339. {
  340.     if (pbData == NULL)
  341.         return;
  342.  
  343.     if (!(afxMemDF & allocMemDF))
  344.     {
  345.         free(pbData);
  346.         return;
  347.     }
  348.  
  349.     struct CBlockHeader* p = ((struct CBlockHeader*) pbData)-1;
  350.  
  351.     // make sure we are freeing what we think we are:
  352.     // error if freeing incorrect memory type such as using
  353.     // delete to deallocate memory that has been allocated
  354.     // with malloc, or vice versa; or using global delete on
  355.     // a CObject derived object; or using CObject delete on
  356.     // a generic memory block.
  357.     ASSERT(p->use == (bIsObject ? CMemoryState::objectBlock 
  358.         : CMemoryState::bitBlock));
  359.  
  360.     // keep track of total amount of memory allocated
  361.     lCurAlloc -= p->nDataSize;
  362.     
  363.     p->use = CMemoryState::freeBlock;
  364.  
  365.     // optionally reclaim memory
  366.     if (!(afxMemDF & delayFreeMemDF))
  367.     {
  368.         // remove from the linked list
  369.         if (p->pBlockHeaderNext)
  370.             p->pBlockHeaderNext->pBlockHeaderPrev = p->pBlockHeaderPrev;
  371.         
  372.         if (p->pBlockHeaderPrev)
  373.         {
  374.             p->pBlockHeaderPrev->pBlockHeaderNext = p->pBlockHeaderNext;
  375.         }
  376.         else
  377.         {
  378.             ASSERT(pFirstBlock == p);
  379.             pFirstBlock = p->pBlockHeaderNext;
  380.         }
  381.  
  382.         // fill the entire block including header with dead-land-fill
  383.         memset(p, bDeadLandFill,
  384.             sizeof(CBlockHeader) + p->nDataSize + nNoMansLandSize);
  385.         free(p);
  386.     }
  387.     else
  388.     {
  389.         // keep memory around as dead space
  390.         memset(p->pbData(), bDeadLandFill, p->nDataSize);
  391.     }
  392. }
  393.  
  394. static BOOL CheckBytes(BYTE* pb, WORD bCheck, size_t nSize)
  395. {
  396.     BOOL bOkay = TRUE;
  397.     while (nSize--)
  398.     {
  399.         if (*pb++ != bCheck)
  400.         {
  401.             TRACE3("memory check error at $%08lX = $%02X, should be $%02X\n",
  402.                 (BYTE FAR*) (pb-1),*(pb-1), bCheck);
  403.             bOkay = FALSE;
  404.         }
  405.     }
  406.     return bOkay;
  407. }
  408.  
  409.  
  410. BOOL AFXAPI AfxCheckMemory()
  411.   // check all of memory (look for memory tromps)
  412. {
  413.     if (!(afxMemDF & allocMemDF))
  414.         return TRUE;        // can't do any checking
  415.  
  416.     BOOL    allOkay = TRUE;
  417.  
  418.     // check all allocated blocks
  419.     struct CBlockHeader* p;
  420.     for (p = pFirstBlock; p != NULL; p = p->pBlockHeaderNext)
  421.     {
  422.         BOOL okay = TRUE;       // this block okay ?
  423.         LPCSTR blockUse;
  424.  
  425.         if (p->use >= 0 && p->use < CMemoryState::nBlockUseMax)
  426.             blockUse = blockUseName[p->use];
  427.         else
  428.             blockUse = szDamage;
  429.  
  430.         // first check no-mans-land gaps
  431.         if (!CheckBytes(p->gap, bNoMansLandFill, nNoMansLandSize))
  432.         {
  433.             TRACE2("DAMAGE: before %Fs block at $%08lX\n", blockUse,
  434.                 (BYTE FAR*) p->pbData());
  435.             okay = FALSE;
  436.         }
  437.  
  438.         if (!CheckBytes(p->pbData() + p->nDataSize, bNoMansLandFill,
  439.           nNoMansLandSize))
  440.         {
  441.             TRACE2("DAMAGE: after %Fs block at $%08lX\n", blockUse,
  442.                 (BYTE FAR*) p->pbData());
  443.             okay = FALSE;
  444.         }
  445.  
  446.         // free blocks should remain undisturbed
  447.         if (p->use == CMemoryState::freeBlock &&
  448.           !CheckBytes(p->pbData(), bDeadLandFill, p->nDataSize))
  449.         {
  450.             TRACE1("DAMAGE: on top of Free block at $%08lX\n",
  451.                 (BYTE FAR*) p->pbData());
  452.             okay = FALSE;
  453.         }
  454.  
  455.         if (!okay)
  456.         {
  457.             // report some more statistics about the broken object
  458.  
  459.             if (p->lpszFileName != NULL)
  460.                 TRACE3("%Fs allocated at file %Fs(%d)\n", blockUse, 
  461.                     p->lpszFileName, p->nLine);
  462.  
  463.             TRACE3("%Fs located at $%08lX is %u bytes long\n", blockUse,
  464.                 (BYTE FAR*) p->pbData(), p->nDataSize);
  465.  
  466.             allOkay = FALSE;
  467.         }
  468.     }
  469.     return allOkay;
  470. }
  471.  
  472.  
  473. // -- true if block of exact size, allocated on the heap
  474. // -- set *plRequestNumber to request number (or 0)
  475. BOOL AFXAPI AfxIsMemoryBlock(const void* pData, UINT nBytes,
  476.         LONG* plRequestNumber)
  477. {
  478.     if (!(afxMemDF & allocMemDF))
  479.     {
  480.         // no tracking memory allocator
  481.         if (plRequestNumber != NULL)
  482.             *plRequestNumber = 0;
  483.         return AfxIsValidAddress(pData, nBytes);    // the best we can do
  484.     }
  485.  
  486.     // otherwise we can check to make sure this was allocated with tracking
  487.     struct CBlockHeader* p = ((struct CBlockHeader*)pData) - 1;
  488.  
  489.     if (AfxIsValidAddress(p, sizeof(CBlockHeader)) &&
  490.         (p->use == CMemoryState::objectBlock ||
  491.             p->use == CMemoryState::bitBlock) &&
  492.         AfxIsValidAddress(pData, nBytes) &&
  493.         p->nDataSize == nBytes)
  494.     {
  495.         if (plRequestNumber != NULL)
  496.             *plRequestNumber = p->lRequest;
  497.         return TRUE;
  498.     }
  499.  
  500.     return FALSE;
  501. }
  502.  
  503. /////////////////////////////////////////////////////////////////////////////
  504. // CMemoryState
  505.  
  506. CMemoryState::CMemoryState()
  507. {
  508.     m_pBlockHeader = NULL;
  509. }
  510.  
  511. // fills 'this' with the difference, returns TRUE if significant
  512. BOOL CMemoryState::Difference(const CMemoryState& oldState,
  513.         const CMemoryState& newState)
  514. {
  515.     BOOL bSignificantDifference = FALSE;
  516.     for (int use = 0; use < CMemoryState::nBlockUseMax; use++)
  517.     {
  518.         m_lSizes[use] = newState.m_lSizes[use] - oldState.m_lSizes[use];
  519.         m_lCounts[use] = newState.m_lCounts[use] - oldState.m_lCounts[use];
  520.  
  521.         if ((m_lSizes[use] != 0 || m_lCounts[use] != 0) &&
  522.           use != CMemoryState::freeBlock)
  523.             bSignificantDifference = TRUE;
  524.     }
  525.     m_lHighWaterCount = newState.m_lHighWaterCount - oldState.m_lHighWaterCount;
  526.     m_lTotalCount = newState.m_lTotalCount - oldState.m_lTotalCount;
  527.  
  528.     return bSignificantDifference;
  529. }
  530.  
  531.  
  532. void CMemoryState::DumpStatistics() const
  533. {
  534.     for (int use = 0; use < CMemoryState::nBlockUseMax; use++)
  535.     {
  536.         TRACE3("%ld bytes in %ld %Fs Blocks\n", m_lSizes[use],
  537.             m_lCounts[use], blockUseName[use]);
  538.     }
  539.  
  540.     TRACE1("Largest number used: %ld bytes\n", m_lHighWaterCount);
  541.     TRACE1("Total allocations: %ld bytes\n", m_lTotalCount);
  542. }
  543.  
  544. // -- fill with current memory state
  545. void CMemoryState::Checkpoint()
  546. {
  547.     if (!(afxMemDF & allocMemDF))
  548.         return;     // can't do anything
  549.  
  550.     m_pBlockHeader = pFirstBlock;
  551.     for (int use = 0; use < CMemoryState::nBlockUseMax; use++)
  552.         m_lCounts[use] = m_lSizes[use] = 0;
  553.  
  554.     struct CBlockHeader* p;
  555.     for (p = pFirstBlock; p != NULL; p = p->pBlockHeaderNext)
  556.     {
  557.         if (p->lRequest == lNotTracked)
  558.         {
  559.             // ignore it for statistics
  560.         }
  561.         else if (p->use >= 0 && p->use < CMemoryState::nBlockUseMax)
  562.         {
  563.             m_lCounts[p->use]++;
  564.             m_lSizes[p->use] += p->nDataSize;
  565.         }
  566.         else
  567.         {
  568.             TRACE1("Bad memory block found at $%08lX\n", (BYTE FAR*) p);
  569.         }
  570.     }
  571.  
  572.     m_lHighWaterCount = lMaxAlloc;
  573.     m_lTotalCount = lTotalAlloc;
  574. }
  575.  
  576. // Dump objects created after this memory state was checkpointed
  577. // Will dump all objects if this memory state wasn't checkpointed
  578. // Dump all objects, report about non-objects also
  579. // List request number in {}
  580. void CMemoryState::DumpAllObjectsSince() const
  581. {
  582.     if (!(afxMemDF & allocMemDF))
  583.     {
  584.         TRACE0("Debugging allocator turned off, can't dump objects\n");
  585.         return;
  586.     }
  587.  
  588.     struct CBlockHeader* pBlockStop;
  589.  
  590.     TRACE0("Dumping objects ->\n");
  591.     pBlockStop = m_pBlockHeader;
  592.  
  593.     struct CBlockHeader* p;
  594.     for (p = pFirstBlock; p != NULL && p != pBlockStop;
  595.         p = p->pBlockHeaderNext)
  596.     {
  597.         char sz[255];
  598.  
  599.         if (p->lRequest == lNotTracked)
  600.         {
  601.             // ignore it for dumping
  602.         }
  603.         else if (p->use == CMemoryState::objectBlock)
  604.         {
  605.             CObject* pObject = (CObject*) p->pbData();
  606.  
  607.             TRACE1("{%ld} ", p->lRequest);
  608.             if (p->lpszFileName != NULL)
  609.             {
  610.                 sprintf(sz, "%Fs(%d) : ", p->lpszFileName, p->nLine);
  611.                 afxDump << (LPCSTR)sz;
  612.             }
  613.  
  614.             if (afxDump.GetDepth() > 0)
  615.             {
  616.                 // long form
  617.                 pObject->Dump(afxDump);
  618.                 afxDump << "\n";
  619.             }
  620.             else
  621.             {
  622.                 // short form
  623.                 sprintf(sz, "a %Fs object at $%08lX, %u bytes long\n",
  624.                     pObject->GetRuntimeClass()->m_lpszClassName,
  625.                     (BYTE FAR*) p->pbData(), p->nDataSize);
  626.                 afxDump << (LPCSTR)sz;
  627.             }
  628.         }
  629.         else if (p->use == CMemoryState::bitBlock)
  630.         {
  631.             TRACE1("{%ld} ", p->lRequest);
  632.             if (p->lpszFileName != NULL)
  633.             {
  634.                 sprintf(sz, "%Fs(%d) : ", p->lpszFileName, p->nLine);
  635.                 afxDump << (LPCSTR)sz;
  636.             }
  637.  
  638.             sprintf(sz, "non-object block at $%08lX, %u bytes long\n",
  639.                 (BYTE FAR*) p->pbData(), p->nDataSize);
  640.             afxDump << (LPCSTR)sz;
  641.         }
  642.     }
  643.     TRACE0("Object dump complete.\n");
  644. }
  645.  
  646. /////////////////////////////////////////////////////////////////////////////
  647. // Enumerate all objects allocated in the diagnostic memory heap
  648.  
  649. void AFXAPI 
  650. AfxDoForAllObjects(void (*pfn)(CObject*, void*), void* pContext)
  651. {
  652.     if (!(afxMemDF & allocMemDF))
  653.         return;         // sorry not enabled
  654.  
  655.     struct CBlockHeader* p;
  656.     for (p = pFirstBlock; p != NULL; p = p->pBlockHeaderNext)
  657.     {
  658.         if (p->lRequest == lNotTracked)
  659.         {
  660.             // ignore it for iteration
  661.         }
  662.         else if (p->use == CMemoryState::objectBlock)
  663.         {
  664.             CObject* pObject = (CObject*) p->pbData();
  665.             (*pfn)(pObject, pContext);
  666.         }
  667.     }
  668. }
  669.  
  670. #endif //_DEBUG
  671.  
  672. /////////////////////////////////////////////////////////////////////////////
  673. // Special hooks for _AFXDLL
  674. // Application exports memory allocator for MFCDLL to use
  675.  
  676. #ifdef _AFXDLL
  677.  
  678. #include <new.h>
  679.  
  680. extern "C"
  681. void* AFX_EXPORT CALLBACK AfxAppAlloc(size_t nBytes)
  682. {
  683. #ifdef _DEBUG
  684.     ASSERT(AfxGetApp() != NULL);
  685.     // jump to appropriate diagnostic allocator and tracking routine
  686.     if (_AfxGetAppDebug()->lpszAllocFileName == NULL)
  687.     {
  688.         if (_AfxGetAppDebug()->bAllocObj)
  689.             return CObject::operator new(nBytes);
  690.         else
  691.             return operator new(nBytes);
  692.     }
  693.     else
  694.     {
  695.         // pass source line info
  696.         if (_AfxGetAppDebug()->bAllocObj)
  697.             return CObject::operator new(nBytes,
  698.                 _AfxGetAppDebug()->lpszAllocFileName,
  699.                 _AfxGetAppDebug()->nAllocLine);
  700.         else
  701.             return operator new(nBytes,
  702.                 _AfxGetAppDebug()->lpszAllocFileName,
  703.                 _AfxGetAppDebug()->nAllocLine);
  704.     }
  705.     //NOTREACHED
  706. #else
  707.     return malloc(nBytes);
  708. #endif
  709. }
  710.  
  711. extern "C"
  712. void AFX_EXPORT CALLBACK AfxAppFree(void* p)
  713. {
  714. #ifdef _DEBUG
  715.     ASSERT(AfxGetApp() != NULL);
  716.     // jump to appropriate diagnostic allocator and tracking routine
  717.     if (_AfxGetAppDebug()->bAllocObj)
  718.         CObject::operator delete(p);
  719.     else
  720.         operator delete(p);
  721. #else
  722.     if (p != NULL)
  723.         free(p);
  724. #endif
  725. }
  726.  
  727. extern "C"
  728. FARPROC AFX_EXPORT CALLBACK AfxAppSetNewHandler(FARPROC pnh)
  729. {
  730.     return (FARPROC)_set_new_handler((_PNH)pnh);
  731. }
  732.  
  733. extern "C"
  734. void* AFX_EXPORT CALLBACK AfxAppReAlloc(void* pOld, size_t nSize)
  735. {
  736.     return realloc(pOld, nSize);
  737. }
  738.  
  739. #endif //_AFXDLL
  740.  
  741.  
  742. /////////////////////////////////////////////////////////////////////////////
  743. // Automatic debug memory diagnostics
  744.  
  745. #ifdef _DEBUG
  746. #ifdef _WINDOWS // AFX_EXITDUMP comes too late for non-Windows app termination
  747.  
  748. class AFX_EXITDUMP
  749. {
  750. public:
  751.     ~AFX_EXITDUMP();
  752. };
  753.  
  754. AFX_EXITDUMP::~AFX_EXITDUMP()
  755. {
  756.     // only dump leaks when there are in fact leaks
  757.     CMemoryState msNow;
  758.     msNow.Checkpoint();
  759.  
  760.     if (msNow.m_lCounts[CMemoryState::objectBlock] != 0 ||
  761.         msNow.m_lCounts[CMemoryState::bitBlock] != 0)
  762.     {
  763.         // dump objects since empty state since difference detected.
  764.         TRACE0("Detected memory leaks!\n");
  765.         afxDump.SetDepth(1);    // just 1 line each
  766.         CMemoryState msEmpty;   // construct empty memory state object
  767.         msEmpty.DumpAllObjectsSince();
  768.     }
  769. }
  770.  
  771. #pragma warning(disable: 4073)  // disable warning about using init_seg
  772. #pragma init_seg(lib)
  773. static AFX_EXITDUMP NEAR afxExitDump;
  774.  
  775. #endif //_WINDOWS
  776. #endif //_DEBUG
  777.  
  778. // NOTE: Do NOT place any new object allocations after this point.  If you
  779. //  do they will be constructed before all other objects -- probably not
  780. //  what you want!
  781.  
  782. /////////////////////////////////////////////////////////////////////////////
  783.