olestuff.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 22k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "priv.h"
  2. #undef new  // Hack!  Need to resolve this.  (edwardp)
  3. #define  _NO_DBGMEMORY_REDEFINITION_
  4. #include "dbgmem.h"
  5. #include <platform.h>
  6. #define DM_MISC2        0   // misc stuff (verbose)
  7. #ifdef DEBUG // {
  8. EXTERN_C LONG g_cmem = 0;
  9. EXTERN_C DWORD g_TlsMem;
  10. // BUGBUG:: Gross but simply a static table of people who registered callbacks...
  11. #define MAX_INTELLI_CALLBACKS 10
  12. // We will psuedo register our own callback as part of this as to remove a lot of special case code...
  13. STDAPI_(void) DumpLeakedMemory(PLEAKMEMINFO pmeminfo);
  14. STDAPI_(LPWSTR) GetLeakSymbolicName(PLEAKMEMINFO pmeminfo, LPWSTR pwszBuf, int cchBuf);
  15. static const INTELLILEAKDUMPCBFUNCTIONS c_ildcbf = {
  16.     DumpLeakedMemory,
  17.     GetLeakSymbolicName
  18. };
  19. int g_cIntelliCallbacks = 1;
  20. struct INTELLILEAKCALLBACKENTRY
  21. {
  22.     HMODULE hmod;
  23.     const INTELLILEAKDUMPCBFUNCTIONS *pfns;
  24. }   g_pfnLeakCallbacks[MAX_INTELLI_CALLBACKS] = {{0, &c_ildcbf}};
  25. STDAPI_(void) _add_to_memlist( HMODULE hmod, void *pv, unsigned int nSize, UINT nType, LPCSTR pszFile, const int iLine )
  26. {
  27.     //  must cache the error so that we can restore it if necessary
  28.     DWORD dwErr = GetLastError();
  29.     HDSA hdsa = (HDSA)TlsGetValue(g_TlsMem);
  30.     if ((hdsa) && (pv)) {
  31.         LEAKMEMINFO memi = { hmod, pv, nSize, nType, pszFile, iLine };
  32.         LEAKMEMINFO *pmemi = &memi;
  33.         if (pmemi->nType == DBGMEM_UNKNOBJ) {
  34. #if ( _X86_) // { QIStub (and GetStackBack) only work for X86
  35.             if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI)) {
  36.             extern void * QIStub_CreateInstance(void* that, IUnknown* punk, REFIID riid);
  37.             HRESULT QISearch(void* that, LPCQITAB pqitab, REFIID riid, void ** ppv);
  38.             // if QIStub is on, our frame should look like:
  39.             //  ... -> leaker -> [SUPER::QI]* -> xxx::QI -> QISearch ->
  40.             //      -> QIStub_CreateInst -> ::new
  41.             // we do our best to follow it back to get to leaker.  getting
  42.             // to xxx::QI is pretty easy, getting thru the SUPER::QI's a
  43.             // bit more iffy (but usually works).
  44.             //
  45.             // note that we need to allow for some fudge since a child
  46.             // returns into the middle of a func (i.e. func+FUDGE), not
  47.             // to the beginning (i.e. func+0).
  48. #define FUDGE(n)    (n)
  49.             //
  50.             // TODO: eventually we may hook up to imagehlp's GetStackBacktrace
  51.             // to give a deeper backtrace, but it's a bit heavyweight.
  52.             int fp, n, i, pfunc;
  53.             struct DBstkback sbtab[6];  // enough for a couple SUPER's
  54.             fp = pmemi->iLine;
  55.             n = DBGetStackBack(&fp, sbtab, ARRAYSIZE(sbtab));
  56. #define INFUNC(p, pfunc, cb)    ((pfunc) <= (p) && (p) <= (pfunc) + (cb))
  57.             // skip over QIStub_CI and QISearch explicitly
  58.             pfunc = (int) QIStub_CreateInstance;
  59.             i = 0;
  60.             if (INFUNC(sbtab[0].ret, (int)QIStub_CreateInstance, FUDGE(16))) {
  61.                 i++;
  62.                 if (INFUNC(sbtab[1].ret, (int)QISearch, FUDGE(512)))
  63.                     i++;
  64.             }
  65.             // skip over any known/suspected QI's
  66.             for ( ; i < n; i++) {
  67.                 if (! DBIsQIFunc(sbtab[i].ret, FUDGE(64)))
  68.                     break;
  69.             }
  70.             TraceMsg(DM_MISC2, "v.atm: n=%d i=%d ret[]=%x,%x,%x,%x,%x,%x", n, i,
  71.                 sbtab[0].ret, sbtab[1].ret, sbtab[2].ret, sbtab[3].ret,
  72.                 sbtab[4].ret, sbtab[5].ret);
  73.             // this should be the leaker
  74.             pmemi->iLine = sbtab[i].ret;
  75.             }
  76.             else
  77.             {
  78.                 // beats me if/why this works for non-x86,
  79.                 // but it's what the old code did
  80.                 pmemi->iLine = *((int *)iLine + 1);     // aka BP_GETRET(iLine)
  81.             }
  82. #else
  83.             // It beats the non-x86 cpus also.
  84.             // Need to fix this  (edwardp).
  85.             pmemi->iLine = 0;
  86. #endif
  87.         }
  88.         if (DSA_AppendItem(hdsa, &memi) >=0) {
  89.             InterlockedIncrement(&g_cmem);
  90.         }
  91.     }
  92.     //  only restore it if it changed, 
  93.     //  that way people with SLE bps wont be startled
  94.     if (dwErr != GetLastError())
  95.         SetLastError(dwErr);
  96. }
  97. void *  __cdecl operator new( size_t nSize, LPCSTR pszFile, const int iLine )
  98. {
  99.     // Zero init just to save some headaches
  100.     void * pv = (void *)LocalAlloc(LPTR, nSize);
  101. #ifdef DEBUG
  102.     HMODULE hmod = 0;
  103.     if (g_bUseNewLeakDetection)
  104.         hmod = HINST_THISDLL;
  105.     add_to_memlist( hmod, pv, nSize, DBGMEM_OBJECT, pszFile, iLine );
  106. #endif
  107.     return pv;
  108. }
  109. void *  __cdecl operator new( size_t nSize )
  110. {
  111.     //
  112.     // HACK!  The compiler is putting hmod as the first local (EBP - 4). So
  113.     // point pstack to &hmod.  We need to get rid of this scumbag code!
  114.     // (edwardp)
  115.     //
  116.     void * pv;
  117. #ifdef DEBUG
  118.     HMODULE hmod = 0;
  119.     LPDWORD pstack = (LPDWORD) &hmod;  // HACK! compiler is putting hmod as first local.
  120. #endif
  121.     // Zero init just to save some headaches
  122.     pv = (void *)LocalAlloc(LPTR, nSize);
  123. #ifdef DEBUG
  124.     if (g_bUseNewLeakDetection)
  125.         hmod = HINST_THISDLL;
  126.     add_to_memlist( hmod, pv, nSize, DBGMEM_UNKNOBJ, "UNKNOWN", (INT_PTR) &pstack[1] );
  127. #endif
  128.     return pv;
  129. }
  130. int _DSA_GetPtrIndex(HDSA hdsa, void* pv)
  131. {
  132.     for (int i=0; i<DSA_GetItemCount(hdsa); i++) {
  133.         LEAKMEMINFO* pmemi = (LEAKMEMINFO*)DSA_GetItemPtr(hdsa, i);
  134.         if (pmemi->pv == pv) {
  135.             return i;
  136.         }
  137.     }
  138.     return -1;
  139. }
  140. STDAPI_(void) _remove_from_memlist(void *pv)
  141. {
  142.     //  must cache the error so that we can restore it if necessary
  143.     DWORD dwErr = GetLastError();
  144.     HDSA hdsa = (HDSA)TlsGetValue(g_TlsMem);
  145.     if (hdsa) {
  146.         int index = _DSA_GetPtrIndex(hdsa, pv);
  147.         if (index >=0) {
  148.             DSA_DeleteItem(hdsa, index);
  149.             InterlockedDecrement(&g_cmem);
  150.         }
  151.     }
  152.     //  only restore it if it changed, 
  153.     //  that way people with SLE bps wont be startled
  154.     if (dwErr != GetLastError())
  155.         SetLastError(dwErr);
  156. }
  157. static UINT g_uMemMove = 0;
  158. STDAPI_(UINT) _mem_thread_message()
  159. {
  160.     if ( !g_uMemMove )
  161.         g_uMemMove = RegisterWindowMessage(TEXT("Shdocvw_ThreadMemTransfer"));
  162.     return g_uMemMove;
  163. }
  164. STDAPI_(void) _transfer_to_thread_memlist(DWORD dwThreadId, void *pv)
  165. {
  166.     UINT uMsg = mem_thread_message();
  167.     //  must cache the error so that we can restore it if necessary
  168.     DWORD dwErr = GetLastError();
  169.     HDSA hdsa = (HDSA)TlsGetValue(g_TlsMem);
  170.     if ( hdsa )
  171.     {
  172.         int index = _DSA_GetPtrIndex( hdsa, pv );
  173.         if ( index >= 0)
  174.         {
  175.             LEAKMEMINFO *pMemBlock = (LEAKMEMINFO*) DSA_GetItemPtr(hdsa, index);
  176.             LEAKMEMINFO *pNewBlock = (LEAKMEMINFO*) LocalAlloc( LPTR, sizeof(LEAKMEMINFO ));
  177.             if ( pNewBlock )
  178.             {
  179.                 *pNewBlock = *pMemBlock;
  180.                 // post a message to the thread giving it the memblock
  181.                 PostThreadMessage( dwThreadId, uMsg, 0, (LPARAM) pNewBlock );
  182.             }
  183.             // remove from the current thread's list...
  184.             DSA_DeleteItem( hdsa, index );
  185.             InterlockedDecrement(&g_cmem);
  186.         }
  187.     }
  188.     //  only restore it if it changed, 
  189.     //  that way people with SLE bps wont be startled
  190.     if (dwErr != GetLastError())
  191.         SetLastError(dwErr);
  192. }
  193. STDAPI_(void) _remove_from_thread_memlist( DWORD dwThreadId, void * pv )
  194. {
  195.     UINT uMsg = mem_thread_message();
  196.     PostThreadMessage( dwThreadId, uMsg, 1, (LPARAM) pv );
  197. }
  198. STDAPI_(void) _received_for_thread_memlist( DWORD dwFlags, void * pData )
  199. {
  200.     //  must cache the error so that we can restore it if necessary
  201.     DWORD dwErr = GetLastError();
  202.     LEAKMEMINFO * pMem = (LEAKMEMINFO *) pData;
  203.     if ( pMem ){
  204.         if ( dwFlags )
  205.         {
  206.             // we are being told to remove it from our thread list because it
  207.             // is actually being freed on the other thread....
  208.             remove_from_memlist( pMem->pv );
  209.             return;
  210.         }
  211.         HDSA hdsa = (HDSA)TlsGetValue(g_TlsMem);
  212.         if (hdsa) {
  213.             if (DSA_AppendItem(hdsa, pMem) >=0) {
  214.                 InterlockedIncrement(&g_cmem);
  215.             }
  216.         }
  217.         LocalFree( pMem );
  218.     }
  219.     //  only restore it if it changed, 
  220.     //  that way people with SLE bps wont be startled
  221.     if (dwErr != GetLastError())
  222.         SetLastError(dwErr);
  223. }
  224. void  __cdecl operator delete(void *pv)
  225. {
  226.     if (pv) {
  227.         remove_from_memlist(pv);
  228.         memset(pv, 0xfe, (UINT)LocalSize((HLOCAL)pv));
  229.         LocalFree((HLOCAL)pv);
  230.     }
  231. }
  232. EXTERN_C int __cdecl _purecall(void) {return 0;}
  233. //***   heuristics {
  234. //***   GetLeakSymbolic -- get human-readable name for object
  235. //
  236. TCHAR *GetLeakSymbolic(LEAKMEMINFO *pLeak)
  237. {
  238.     extern TCHAR *DBGetQIStubSymbolic(void* that);
  239.     extern TCHAR *DBGetClassSymbolic(int cbSize);
  240.     TCHAR *pszSym;
  241. #if ( _X86_) // { QIStub only works for X86
  242.     if (pLeak->nType == DBGMEM_UNKNOBJ && DBIsQIStub(pLeak->pv))
  243.         pszSym = DBGetQIStubSymbolic(pLeak->pv);
  244.     else
  245. #endif // }
  246.     if (pszSym = DBGetClassSymbolic(pLeak->cb))
  247.         ;
  248.     else {
  249.         // if you get this string, go into debdump.cpp and add a
  250.         // DBGetClassSymbolic table entry for the class
  251.         pszSym = TEXT("?debdump!DBGetClassSymbolic");
  252.     }
  253.     return pszSym;
  254. }
  255. //***   _ConvertHModToIntelliDumpIndex
  256. // DESCRIPTION
  257. //  main heuristics:
  258. int _ConvertHModToIntelliDumpIndex(HMODULE hmod)
  259. {
  260.     for (int i = 0; i < g_cIntelliCallbacks; i++) {
  261.         if ((hmod == g_pfnLeakCallbacks[i].hmod) &&
  262.                 !IsBadCodePtr((FARPROC)g_pfnLeakCallbacks[i].pfns->pfnDumpLeakedMemory)) {
  263.             return i;
  264.         }
  265.     }
  266.     return -1;
  267. }
  268. //***   _DoDumpMemLeakIntelli -- attempt to interpret leak info
  269. // DESCRIPTION
  270. //  main heuristics:
  271. //      try to detect refs from one object to another by walking all DWORDs
  272. //          this gives us a graph description
  273. //          more importantly, it tells us which are the 'root' leaks
  274. //      identify classes so we can label them w/ a symbolic name
  275. //      identify QIStub's so we can dump them nicely
  276. //          e.g. symbolic IID and a sequence # for that IID
  277. //          the sequence # can be used to find the exact QI call
  278. //  others:
  279. //      see the code (sorry)...
  280. // NOTES
  281. //  algorithm is n^2, so sue me...
  282. //  we assume (hopefully correctly...) that all memory is aligned to a
  283. //  'strict' boundary so we'll never fault dereferencing DWORDs.  if that
  284. //  turns out to be wrong we can wrap in a __try...__except.
  285. void _DoDumpMemLeakIntelli(HDSA hdsa, DWORD wFlags)
  286. {
  287.     int cLeak;
  288.     ASSERT(wFlags & DML_END);
  289.     ASSERT(hdsa);
  290.     cLeak = DSA_GetItemCount(hdsa);
  291.     if (!cLeak)
  292.         return;
  293.     TraceMsg(TF_ALWAYS, "intelli-leak heuristics...");
  294.     for (int iDef = 0; iDef < cLeak; iDef++) {
  295.         LEAKMEMINFO* pDef = (LEAKMEMINFO*)DSA_GetItemPtr(hdsa, iDef);
  296.         BOOL fHasRef;
  297.         int iDumpModule;
  298.         if (IsBadReadPtr(pDef->pv, pDef->cb))
  299.             continue;
  300.         // see if we should hand this one off to a different dumper?
  301.         if ((iDumpModule = _ConvertHModToIntelliDumpIndex(pDef->hmod)) >= 0) {
  302.             g_pfnLeakCallbacks[iDumpModule].pfns->pfnDumpLeakedMemory(pDef);
  303.         }
  304.         else {
  305.             ASSERT(FALSE);
  306.         }
  307.         // find all (likely) refs to this leak.  we do this by walking
  308.         // the full set of leaks and looking for DWORDs that point to
  309.         // the base of this leak.  we only look at the base on the
  310.         // assumption that ptrs will go thru QIStub's (and this bounds
  311.         // the search which is nice).
  312.         fHasRef = FALSE;
  313.         for (int iRef = 0; iRef < cLeak; iRef++) {
  314.             LEAKMEMINFO* pRef = (LEAKMEMINFO*)DSA_GetItemPtr(hdsa, iRef);
  315.             int dOff;
  316.             if (IsBadReadPtr(pRef->pv, pRef->cb))
  317.                 continue;
  318. #define TRUNCPOW2(n, p)     ((n) & ~((p) - 1))
  319.             dOff = SearchDW((DWORD*)pRef->pv, TRUNCPOW2(pRef->cb, SIZEOF(DWORD)), PtrToLong(pDef->pv));
  320.             if (dOff != -1) {
  321.                 // found a ref to the leak def!
  322.                 if ((iDumpModule = _ConvertHModToIntelliDumpIndex(pRef->hmod)) >= 0) {
  323.                     WCHAR szBuf[80];
  324.                     LPWSTR pwszRef = g_pfnLeakCallbacks[iDumpModule].pfns->pfnGetLeakSymbolicName(pDef,
  325.                             szBuf, ARRAYSIZE(szBuf));
  326.                     TraceMsg(TF_ALWAYS, "tref=%x,%x+%x(%ls)",
  327.                         pRef->pv, pRef->cb, dOff, pwszRef);
  328.                 }
  329.                 else {
  330.                     ASSERT(FALSE);
  331.                 }
  332.                 // a fair number of objects actually point back to themselves
  333.                 // print out the ref just in case, but don't count it as a
  334.                 // real one (which will make us look like a non-root)
  335.                 if (pRef->pv != pDef->pv)
  336.                     fHasRef = TRUE;
  337.                 else
  338.                     TraceMsg(TF_ALWAYS, "tref=self");
  339.                 // (we could iterate on pRef->pv+dOff+SIZEOF(DWORD),
  340.                 // but probably the 1st hit is all we need)
  341.             }
  342.         }
  343.         if (!fHasRef) {
  344.             // these are the guys we really care about
  345.             TraceMsg(TF_ALWAYS, "tref=root ***");
  346.         }
  347.     }
  348.     // drop into debugger for further analysis
  349.     ASSERT_MSG(0, "Take this opportunity to debug the leak");
  350.     
  351.     return;
  352. }
  353. // }
  354. void _DoDumpMemLeak(HDSA hdsa, DWORD wFlags)
  355. {
  356.     BOOL fLeaked = FALSE;
  357.     ASSERT(wFlags & DML_END);
  358.     ASSERT(hdsa);
  359.     if (DSA_GetItemCount(hdsa)) {
  360.         // Let's always dump them.
  361.         TraceMsg(TF_ALWAYS, "****************************************************");
  362.         TraceMsg(TF_ALWAYS, "*    !!!!! WARNING : MEMORY LEAK DETECTED !!!!!    *");
  363.         TraceMsg(TF_ALWAYS, "****************************************************");
  364.         TraceMsg(TF_ALWAYS, "* For Object: address: Vtbl, ...Vtbl, _cRef        *");
  365.         TraceMsg(TF_ALWAYS, "* For StrDup: address: 'text'                      *");
  366.         TraceMsg(TF_ALWAYS, "* For Traced: address:                             *");
  367.         TraceMsg(TF_ALWAYS, "* For Memory: address:                             *");
  368.         TraceMsg(TF_ALWAYS, "****************************************************");
  369.         {
  370.             for (int i=0; i<DSA_GetItemCount(hdsa); i++) {
  371.                 LEAKMEMINFO* pmemi = (LEAKMEMINFO*)DSA_GetItemPtr(hdsa, i);
  372.                 DWORD* pdw = (DWORD*)pmemi->pv;
  373.                 // sometimes we think we have leaked something and its really been freed,
  374.                 // so check here first
  375.                 if (IsBadReadPtr((void *)pdw, pmemi->cb))
  376.                     continue;
  377.                 switch( pmemi->nType ) {
  378.                 case DBGMEM_STRDUP:
  379.                     TraceMsgA(TF_ALWAYS, "StrDup: %8x: "%s"ntt size=%d (%s, line %d)",
  380.                              pdw, pdw, pmemi->cb, PathFindFileNameA(pmemi->pszFile), pmemi->iLine);
  381.                     break;
  382.                 case DBGMEM_UNKNOBJ:
  383.                 case DBGMEM_OBJECT:
  384.                     {
  385.                         if ( pmemi->cb >= 32 )
  386.                         {
  387.                             TraceMsg(TF_ALWAYS, "Object: %8x: %8x %8x %8x %8x",
  388.                                 pdw, pdw[0], pdw[1], pdw[2], pdw[3] );
  389.                         }
  390.                         else
  391.                         {
  392.                             TraceMsg(TF_ALWAYS, "Object: %8x: Size<32 bytes. No Vtbl.", pdw );
  393.                         }
  394.                     }
  395.                     break;
  396.                 case DBGMEM_TRACED:
  397.                     TraceMsg(TF_ALWAYS, "Traced: %8x:", pdw );
  398.                     break;
  399.                 case DBGMEM_MEMORY:
  400.                 default:
  401.                     TraceMsg(TF_ALWAYS, "Memory: %8x:", pdw );
  402.                     break;
  403.                 }
  404.                 if ( pmemi->nType == DBGMEM_UNKNOBJ )
  405.                 {
  406.                     TraceMsg(TF_ALWAYS, "t size=%d, created from %8x (return address)",
  407.                                      pmemi->cb, pmemi->iLine);
  408.                 }
  409.                 else
  410.                 {
  411.                     TraceMsgA(TF_ALWAYS, "t size=%d  (%s, line %d)",
  412.                                      pmemi->cb, PathFindFileNameA(pmemi->pszFile), pmemi->iLine);
  413.                 }
  414.             }
  415.         }
  416.         TraceMsg(TF_ALWAYS, "*************************************************");
  417.         AssertMsg(0, TEXT("*** ALL MEMORY LEAK MUST BE FIXED BEFORE WE RELEASE (continue for intelli-leak on x86) ***"));
  418.         fLeaked = TRUE;
  419.     }
  420.     if (!fLeaked) {
  421.         TraceMsg(TF_GENERAL, "Thread Terminated: -- No Memory Leak Detected for this thread --");
  422.     }
  423. }
  424. void _DumpMemLeak(DWORD wFlags)
  425. {
  426.     HDSA hdsa;
  427.     if (wFlags & DML_END) {
  428.         hdsa = (HDSA)TlsGetValue(g_TlsMem);
  429.         if (hdsa) {
  430.             _DoDumpMemLeak(hdsa, wFlags);
  431.             _DoDumpMemLeakIntelli(hdsa, wFlags);
  432.             DSA_Destroy(hdsa);
  433.             TlsSetValue(g_TlsMem, NULL);
  434.         }
  435.     } else {
  436.         hdsa = DSA_Create(SIZEOF(LEAKMEMINFO),8);
  437.         TlsSetValue(g_TlsMem, (void *)hdsa);
  438.     }
  439. }
  440. STDAPI_(void) _DebugMemLeak(UINT wFlags, LPCTSTR pszFile, UINT iLine)
  441. {
  442.     LPCTSTR pszSuffix = (wFlags & DML_END) ? TEXT("END") : TEXT("BEGIN");
  443.     switch(wFlags & DML_TYPE_MASK) {
  444.     case DML_TYPE_MAIN:
  445.         _DumpMemLeak(wFlags);
  446.         if (g_cmem) {
  447.             AssertMsg(0, TEXT("MAIN: %s, line %d: %d blocks of C++ objects left in memory. Read shdocvw") TEXT(FILENAME_SEPARATOR_STR) TEXT("memleak.txt for detail"),
  448.                      PathFindFileName(pszFile), iLine, g_cmem);
  449.         }
  450.         break;
  451.     case DML_TYPE_THREAD:
  452.         if (g_tidParking != GetCurrentThreadId())
  453.             _DumpMemLeak(wFlags);
  454.         break;
  455.     case DML_TYPE_NAVIGATE:
  456.         TraceMsg(TF_SHDLIFE, "NAVIGATEW_%s: %s, line %d: %d blocks of C++ objects in memory",
  457.                      pszSuffix, PathFindFileName(pszFile), iLine, g_cmem);
  458.         break;
  459.     }
  460. }
  461. // LocalXXXXX functions
  462. STDAPI_(HLOCAL) _TrcLocalAlloc(
  463.     UINT uFlags,                            // flags used in LocalAlloc
  464.     UINT uBytes,                            // number of bytes to be allocated
  465.     LPCSTR pszFile,                         // file which allocced memory
  466.     const int iLine                         // line which allocced memory
  467.     )
  468. {
  469.     HLOCAL lpv = (HLOCAL) LocalAlloc( uFlags, uBytes );
  470.     if ( lpv )
  471.         add_to_memlist( 0, lpv, uBytes, DBGMEM_MEMORY, pszFile, iLine );
  472.     return lpv;
  473. }
  474. STDAPI_(LPTSTR)  _TrcStrDup(
  475.     LPTSTR lpSrch,                          // pointer to string to StrDup
  476.     LPCSTR pszFile,                         // file which allocced memory
  477.     const int iLine                         // line which allocced memory
  478.     )
  479. {
  480.     UINT uBytes = 0;
  481.     if ( lpSrch )
  482.         uBytes = lstrlen( lpSrch ) + 1;
  483.     LPTSTR lpstr = StrDup( lpSrch );
  484.     if ( lpstr )
  485.         add_to_memlist( 0, lpstr, uBytes, DBGMEM_STRDUP, pszFile, iLine );
  486.     return lpstr;
  487. }
  488. STDAPI_(HLOCAL) _TrcLocalFree(
  489.     HLOCAL hMem                             // memory to be freed
  490.     )
  491. {
  492.     if ( hMem )
  493.     {
  494.         remove_from_memlist( hMem );
  495.         memset( hMem, 0xfe, (UINT)LocalSize( hMem ));
  496.     }
  497.     return LocalFree( hMem );
  498. }
  499. STDAPI_(void)  _register_intelli_dump(HMODULE hmod, const INTELLILEAKDUMPCBFUNCTIONS *pfns)
  500. {
  501.     if (g_cIntelliCallbacks < (MAX_INTELLI_CALLBACKS - 1))
  502.     {
  503.         g_pfnLeakCallbacks[g_cIntelliCallbacks].hmod = hmod;
  504.         g_pfnLeakCallbacks[g_cIntelliCallbacks].pfns = pfns;
  505.         g_cIntelliCallbacks++;
  506.     }
  507. }
  508. #else // }{
  509. #define CPP_FUNCTIONS
  510. #include <crtfree.h>
  511. #endif // }
  512. BOOL GetLeakDetectionFunctionTable(LEAKDETECTFUNCS *pTable)
  513. {
  514. #ifdef DEBUG
  515.     if(pTable)
  516.     {
  517.         pTable->pfnDumpMemLeak = _DumpMemLeak;
  518.         pTable->pfnTrcLocalAlloc = _TrcLocalAlloc;
  519.         pTable->pfnTrcLocalFree = _TrcLocalFree;
  520.         pTable->pfnTrcStrDup = _TrcStrDup;
  521.         pTable->pfnDumpMemLeak = _DumpMemLeak;
  522.         pTable->pfnDebugMemLeak = MemLeakInit; //_DebugMemLeak;
  523.         pTable->pfnreceived_for_thread_memlist = received_for_thread_memlist;
  524.         pTable->pfnremove_from_thread_memlist = remove_from_thread_memlist;
  525.         pTable->pfnmem_thread_message = mem_thread_message;
  526.         pTable->pfnremove_from_memlist = remove_from_memlist;
  527.         pTable->pfnadd_to_memlist = add_to_memlist;
  528.         pTable->pfnregister_hmod_intelli_dump = register_intelli_dump;
  529.         return TRUE;
  530.     }
  531.     else
  532.     {
  533.         return FALSE;
  534.     }
  535. #else
  536.     return FALSE;
  537. #endif
  538. }
  539. // We export all the memory leak detection functions in the form of a table of
  540. // pointers so that all other shell components can share in the same leak
  541. // detection code
  542. // -----------------------------------------------------------------------------
  543. // These two functions are our DLLS callback functions to dump the acutal leaks...
  544. #ifdef DEBUG
  545. //***   GetLeakSymbolicName
  546. // DESCRIPTION
  547. STDAPI_(LPWSTR) GetLeakSymbolicName(PLEAKMEMINFO pmeminfo, LPWSTR pwszBuf, int cchBuf)
  548. {
  549.     LPTSTR pszDef = GetLeakSymbolic(pmeminfo);     // human-readable name
  550.         // they only want the class name...
  551.     return pszDef;
  552. }
  553. //***   Dump LeakedMemory
  554. // DESCRIPTION
  555. STDAPI_(void) DumpLeakedMemory(LEAKMEMINFO* pmeminfo)
  556. {
  557.     LPTSTR pszDef = GetLeakSymbolic(pmeminfo);     // human-readable name
  558.     TraceMsg(TF_ALWAYS, "leak=0x%x,%x(%s)", pmeminfo->pv, pmeminfo->cb, pszDef);
  559.     if (pmeminfo->nType == DBGMEM_UNKNOBJ)
  560.         TraceMsg(TF_ALWAYS, "tcreated from 0x%x", pmeminfo->iLine);
  561.     else
  562.         TraceMsgA(TF_ALWAYS, "tcreated from %hs:%d",
  563.              PathFindFileNameA(pmeminfo->pszFile), pmeminfo->iLine);
  564. #if ( _X86_) // { QIStub only works for X86
  565.     if (pmeminfo->nType == DBGMEM_UNKNOBJ && DBIsQIStub(pmeminfo->pv)) {
  566.         // it's a QIStub, dump it
  567.         // of particular interest is the 'sequence #' (esp. for roots)
  568.         DBDumpQIStub(pmeminfo->pv);
  569.     }
  570. #endif // }
  571. }
  572. #endif