home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc Source Code / Memory / MemDebg.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-22  |  15.9 KB  |  617 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        MemDebg.cpp
  3.  
  4.     Contains:    Memory management debug routine implementations
  5.  
  6.     Owned by:    Jens Alfke
  7.     Owned by:    Jens Alfke, Vincent Lo, Nick Pilch, Michael Burbidge
  8.  
  9.     Copyright:    © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
  10.  
  11.     Change History (most recent first):
  12.  
  13.         <23>     10/3/95    TJ        Opps, I had left some code in that had been
  14.                                     if defed out.
  15.         <22>     10/3/95    TJ        Changes done by RefBall Team
  16.         <21>      8/8/95    TJ        Declared FindLeaksProc extern C
  17.         <20>      8/7/95    TJ        Typecast &InitLeaksProc to
  18.                                     (MMBlockInfoProc) for the MMWalkHeap call
  19.                                     so it will compile with SCpp.
  20.         <19>      8/4/95    DM        Leak checking [1267956]
  21.         <18>     6/21/95    JBS        turn off heap validation for ∂SOM data xfer
  22.         <17>      6/7/95    jpa        Changed old (pre-SLIM) SOM includes to
  23.                                     som.xh [1256901]
  24.         <16>      5/4/95    jpa        Added MMFindBlockContaining [1246077]
  25.         <15>    12/20/94    jpa        Add stub routines in non-debug config so
  26.                                     library will build. [1188344]
  27.         <14>     12/5/94    jpa        Nuked errant pragma lib_export's. [1195676]
  28.         <13>    10/24/94    jpa        Constness [1194286]
  29.         <12>     9/29/94    RA        1189812: Mods for 68K build.
  30.         <11>     9/20/94    VL        jpa: Fixed infinite recursion in heap
  31.                                     validation.
  32.         <10>     9/14/94    jpa        Eliminated dependencies on rest of OpenDoc.
  33.                                     OD-->MM. [1186692]
  34.          <9>      9/9/94    jpa        Made ODValidatePtr more robust.
  35.          <8>     8/19/94    NP        1181622: Ownership fix.
  36.          <7>     8/17/94    jpa        Added ODWalkHeap, greatly improved
  37.                                     ODValidateObject, and added debugging
  38.                                     checks using the SOM-block flag. [1179567]
  39.          <6>      8/8/94    jpa        Added ODGetHeapInfo. [1179567]
  40.          <5>      8/2/94    jpa        Plenty more fixes to validation.
  41.          <4>     7/26/94    jpa        Got validation stuff to work again.
  42.          <3>     6/18/94    MB        Include MemDebgP.h
  43.          <2>     6/10/94    MB        Make it build
  44.          <1>      6/9/94    MB        first checked in
  45.          <3>     5/27/94    jpa        New exception support [1165267]
  46.          <2>     5/27/94    MB        #1162181: Fixed MMM integration bug
  47.          <1>     5/27/94    MB        first checked in
  48.     To Do:
  49.     
  50.     In Progress:
  51.         
  52. */
  53.  
  54. #ifndef _MEMCNFIG_
  55. #include "MemCnfig.h"
  56. #endif
  57.  
  58. #ifndef _MEMDEBG_
  59. #include "MemDebg.h"
  60. #endif
  61.  
  62.  
  63. #if MM_DEBUG
  64.  
  65.  
  66. #ifndef _MEMMGRPV_
  67. #include "MemMgrPv.h"
  68. #endif
  69.  
  70. #ifndef _MEMHOOKS_
  71. #include "MemHooks.h"
  72. #endif
  73.  
  74. #include <string.h>
  75.  
  76. #ifndef __SOM__
  77. #include <som.xh>
  78. #endif
  79.  
  80. #include <SOMObj.xh>
  81.  
  82. #ifndef _CRAWL_
  83. #include "Crawl.h"
  84. #endif
  85.  
  86. #ifndef __LOWMEM__
  87. #include <LowMem.h>
  88. #endif
  89.  
  90.  
  91. //==============================================================================
  92. // Global variable definitions
  93. //==============================================================================
  94.  
  95. MMBoolean gValidate = 0;
  96. MMBoolean gHeapChecking = 0;
  97.  
  98.  
  99. //==============================================================================
  100. // Function definitions
  101. //==============================================================================
  102.  
  103.  
  104. //------------------------------------------------------------------------------
  105. // DoesHeapExist
  106. //------------------------------------------------------------------------------
  107.  
  108. MMBoolean MMDoesHeapExist( MemHeap *heap )
  109. {
  110.     if( ((MemoryHeap*)heap)->GetLocation()==kMMSysMemory )
  111.         return kMMTrue;        // A system heap might have been allocated by another process.
  112.         
  113.     for( MemoryHeap *h = MemoryHeap::GetFirstHeap(); h; h = h->GetNextHeap() )
  114.         if( h == (MemoryHeap*)heap )
  115.             return kMMTrue;
  116.     return kMMFalse;
  117. }
  118.  
  119. //------------------------------------------------------------------------------
  120. // MMBeginMemValidation
  121. //------------------------------------------------------------------------------
  122.  
  123. void
  124. MMBeginMemValidation( )
  125. {
  126.     MMValidateAllHeaps();
  127.     if( gValidate==0 )
  128.         for( MemoryHeap *h = MemoryHeap::GetFirstHeap(); h; h = h->GetNextHeap() ) {
  129.             h->SetZapOnAllocate(kMMTrue);
  130.             h->SetZapOnFree(kMMTrue);
  131.             h->SetAutoValidation(kMMTrue);
  132.         }
  133.     gValidate++;
  134. }
  135.  
  136. //------------------------------------------------------------------------------
  137. // MMEndMemValidation
  138. //------------------------------------------------------------------------------
  139.  
  140. void
  141. MMEndMemValidation( )
  142. {
  143.     if( gValidate<=0 ) {
  144.         MM_WARN("Improper nesting of memory-validation calls");
  145.         return;
  146.     }
  147.     
  148.     MMValidateAllHeaps();
  149.     gValidate--;
  150.     if (gValidate==0)
  151.         for( MemoryHeap *h = MemoryHeap::GetFirstHeap(); h; h = h->GetNextHeap() ) {
  152.             h->SetZapOnAllocate(kMMFalse);
  153.             h->SetZapOnFree(kMMFalse);
  154.             h->SetAutoValidation(kMMFalse);
  155.         }
  156. }
  157.  
  158. //------------------------------------------------------------------------------
  159. // MMBeginHeapChecking
  160. //------------------------------------------------------------------------------
  161.  
  162. void
  163. MMBeginHeapChecking( )
  164. {
  165.     gHeapChecking++;
  166.     MMBeginMemValidation();
  167. }
  168.  
  169. //------------------------------------------------------------------------------
  170. // MMEndHeapChecking
  171. //------------------------------------------------------------------------------
  172.  
  173. void
  174. MMEndHeapChecking( )
  175. {
  176.     if( gHeapChecking<=0 ) {
  177.         MM_WARN("Improper nesting of heap-checking calls");
  178.         return;
  179.     }
  180.     
  181.     gHeapChecking--;
  182.     MMEndMemValidation();
  183. }
  184.  
  185. //------------------------------------------------------------------------------
  186. // MMValidateHeap
  187. //------------------------------------------------------------------------------
  188.  
  189. static Boolean
  190. HeapCheckProc( const void *blk, unsigned long /*size*/, Boolean isObject, void *refCon )
  191. {
  192.     if( isObject ) {
  193.         (*(MMULong*)refCon) ++;                            // Increment object count
  194.         MMValidateObject((SOMObject*)blk);
  195.     }
  196.     return true;
  197. }
  198.  
  199.  
  200. MMBoolean
  201. MMValidateHeap( MemHeap *heapID, const void* ptr )
  202. {
  203.     if (!heapID )
  204.         heapID = MMGetDefaultHeap();
  205.  
  206.     MM_ASSERT(heapID);
  207.     
  208. #if 0
  209.     if (!MMDoesHeapExist(heapID)) {
  210.         if( ptr )
  211.             MM_WARN("%p's heap at %p is unknown", ptr,heapID);
  212.         else
  213.             MM_WARN("%p is not a known heap", heapID);
  214.         return kMMFalse;
  215.     }
  216. #endif
  217.  
  218.     MMULong objects = 0;
  219.     ((MemoryHeap*)heapID)->Check(&HeapCheckProc,&objects);
  220.     
  221.     return kMMTrue;
  222. }
  223.  
  224.  
  225. //------------------------------------------------------------------------------
  226. // MMValidateAllHeaps
  227. //------------------------------------------------------------------------------
  228.  
  229. MMBoolean
  230. MMValidateAllHeaps( )
  231. {
  232.     MMBoolean result = kMMTrue;
  233.     for( MemoryHeap *h = MemoryHeap::GetFirstHeap(); h; h = h->GetNextHeap() )
  234.         if( !MMValidateHeap((MemHeap*)h) )
  235.             result = kMMFalse;
  236.     return result;
  237. }
  238.  
  239.  
  240. //------------------------------------------------------------------------------
  241. // MMValidatePtr
  242. //------------------------------------------------------------------------------
  243.  
  244. MMBoolean
  245. MMValidatePtr( const void* p, MMBoolean validateHeap, const char *operation )
  246. {
  247.     // If we could be sure that p were in the app zone, we could be more
  248.     // stringent. But it might be in the System heap or in temp-mem.
  249.     
  250.     const char *err = BasicValidatePtr(p);
  251.     if( !err ) {
  252.         BestFitHeap *heap = (BestFitHeap*) gDefaultHeap->GetBlockHeap(p);
  253.         
  254. #if 0
  255.         if (!MMDoesHeapExist((MemHeap*)heap))
  256.             if( operation )
  257.                 MM_WARN("%s(%p): block's heap %p is unknown", operation,p,heap);
  258.             else
  259.                 MM_WARN("%p's heap %p is unknown", p,heap);
  260. #endif
  261.         
  262.         if( !heap->IsValidBlock(p) ) {
  263.             err = "is invalid";
  264.             if( somIsObj((void*)p) ) {
  265.                 MM_WARN("Invalid block %p is an object of class %s",
  266.                             p, ((SOMObject*)p)->somGetClassName() );
  267.             }
  268.         } else if( validateHeap && !MMValidateHeap((MemHeap*)heap,p) )
  269.             return kMMFalse;    // ODValidateHeap already warns the user
  270.         else
  271.             return kMMTrue;
  272.     }
  273.     
  274.     if( operation )
  275.         MM_WARN("%s(%p): ptr %s!",operation,p,err);
  276.     else
  277.         MM_WARN("Pointer %p %s!",p,err);
  278.     return kMMFalse;
  279. }
  280.  
  281.  
  282. //------------------------------------------------------------------------------
  283. // MMValidateObject
  284. //------------------------------------------------------------------------------
  285.  
  286. static MMBoolean
  287. BasicIsObject( const void *block )
  288. {
  289.     // This is like MMIsObject but does not do any heap checking, which would
  290.     // be fatal if MMValidateObject were already being called during a heap-check!
  291.     
  292.     MemoryHeap *heap = gDefaultHeap->GetBlockHeap(block);
  293.     return heap ?heap->BlockIsObject(block) :kMMFalse;
  294. }
  295.  
  296. MMBoolean
  297. MMValidateObject( const SOMObject *o )
  298. {
  299.     // I mustn't check the heap, since I am called during heap checking!!
  300.     if( !MMValidatePtr(o,kMMFalse,"MMValidateObject") )
  301.         return kMMFalse;
  302.     
  303.     const char *err;
  304.     if( !BasicIsObject(o) )
  305.         err = "is not marked as an object in the heap";
  306.     else if( !gHaveSOM || !somIsObj((SOMObject*)o) )
  307.         err = "is not a SOM object";
  308.     else
  309.         return kMMTrue;
  310.     
  311.     MM_WARN("Object %p %s!", o, err);
  312.     return kMMFalse;
  313. }
  314.  
  315. //------------------------------------------------------------------------------
  316. // MMGetHeapInfo
  317. //------------------------------------------------------------------------------
  318.  
  319. void
  320. MMGetHeapInfo( MemHeap *heapID,
  321.                 const char* *name, size_t *allocated, size_t *free,
  322.                 size_t *nBlocks, size_t *nObjects )
  323. {
  324.     MemoryHeap *heap = (MemoryHeap*)( heapID ?heapID :MMGetDefaultHeap() );
  325.     
  326.     if( name )        *name = heap->GetDescription();
  327.     if( allocated )    *allocated = heap->BytesAllocated();
  328.     if( free )        *free = heap->BytesFree();
  329.     if( nBlocks )    *nBlocks = heap->NumberAllocatedBlocks();
  330.     
  331.     if( nObjects ) {
  332.         *nObjects = 0;
  333.         heap->Check(&HeapCheckProc,&*nObjects);
  334.     }
  335. }
  336.  
  337.  
  338. //------------------------------------------------------------------------------
  339. // MMWalkHeap
  340. //------------------------------------------------------------------------------
  341.  
  342. struct HeapWalkData {
  343.     MMBlockInfoProc proc;
  344.     void *refCon;
  345. };
  346.  
  347. static Boolean CallHeapWalkProc( void *blk, unsigned long size, Boolean isObject,
  348.                                  void *refCon )
  349. {
  350.     if( isObject )
  351.         MMValidateObject((SOMObject*)blk);
  352.     else
  353.         MMValidatePtr(blk,false);
  354.         
  355.     HeapWalkData *data = (HeapWalkData*) refCon;
  356.     return (data->proc) (blk, size, isObject, data->refCon);
  357. }
  358.  
  359.  
  360.  
  361. void
  362. MMWalkHeap( MemHeap *heapID, MMBlockInfoProc proc, void *refCon )
  363. {
  364.     MemoryHeap *heap = (MemoryHeap*)( heapID ?heapID :MMGetDefaultHeap() );
  365.     
  366.     HeapWalkData data;
  367.     data.proc = proc;
  368.     data.refCon = refCon;
  369.     heap->Check((HeapWalkProc)CallHeapWalkProc,&data);
  370. }
  371.  
  372. MMBoolean
  373. MMFindBlockContaining( const void *start, const void *end,
  374.                        const void* *blockStart, const void* *blockEnd )
  375. {
  376.     const void *foo, *bar;
  377.     if( !blockStart ) blockStart=&foo;
  378.     if( !blockEnd   ) blockEnd=&bar;
  379.         
  380.     if( end<start ) {
  381.         const void *temp = end;
  382.         end = start;
  383.         start = temp;
  384.     }
  385.  
  386.     MemoryHeap *heap = (MemoryHeap*)MMGetDefaultHeap();
  387.     return heap->FindBlockContaining(start,end,*blockStart,*blockEnd);
  388. }
  389.  
  390.  
  391. MMBoolean
  392. MMValidateMemoryRange( const void *start, const void *end )
  393. {
  394.     // Warn if memory range is in default heap but not entirely within a valid block:
  395.     if( end<start ) {
  396.         const void *temp = end;
  397.         end = start;
  398.         start = temp;
  399.     }
  400.     const void *blockStart, *blockEnd;
  401.     MemoryHeap *heap = (MemoryHeap*)MMGetDefaultHeap();
  402.     if( heap->FindBlockContaining(start,end, blockStart,blockEnd) )
  403.         if( blockStart==NULL ) {
  404.             MM_WARN("Mem range %p--%p is in heap but not in any block", start,end);
  405.             return kMMFalse;
  406.         } else if( start<blockStart || end>blockEnd ) {
  407.             MM_WARN("Mem range %p--%p violates block %p--%p",
  408.                     start,end, blockStart,blockEnd);
  409.             return kMMFalse;
  410.         }
  411.     return kMMTrue;
  412. }
  413.  
  414.  
  415. //========================================================================================
  416. // Block Stack Crawls
  417. //========================================================================================
  418.  
  419. MMBoolean
  420. MMTrackStackCrawls( MMBoolean track )
  421. {
  422.     MMBoolean old = CBlockStackCrawlHook::gTrack;
  423.     CBlockStackCrawlHook::gTrack = track;
  424.     return old;
  425. }
  426.  
  427.  
  428. StackCrawl*
  429. MMGetBlockStackCrawl( const void *block, long *flags )
  430. {
  431.     BestFitHeap *heap = GetHeap(block,"MMGetBlockStackCrawl");
  432.     if( heap ) {
  433.         size_t s = (size_t) heap->GetBlockStackCrawl(block);
  434.         if( flags ) *flags = s & 3;
  435.         return (StackCrawl*)( s & ~3L );
  436.     } else {
  437.         if( flags ) *flags = 0;
  438.         return NULL;
  439.     }
  440. }
  441.  
  442.  
  443. void
  444. MMSetBlockStackCrawl( const void *block, StackCrawl *s, long flags )
  445. {
  446.     BestFitHeap *heap = GetHeap(block,"MMSetBlockStackCrawl");
  447.     if( heap )
  448.         heap->SetBlockStackCrawl( block, (StackCrawl*)( (size_t)s | (flags & 3)) );
  449. }
  450.  
  451.  
  452. //========================================================================================
  453. // Memory Leak Detection
  454. //========================================================================================
  455.  
  456.  
  457. struct LeakLink {
  458.     LeakLink*        fNext;
  459.     const void*        fFirstBlock;
  460.     StackCrawl*        fStack;
  461.     unsigned long    fCount;
  462. };
  463.  
  464. static LeakLink *sLeakLinks;
  465.  
  466.  
  467. static MMBoolean InitLeaksProc(  const void *blk, size_t size, MMBoolean isObject,
  468.                                     void *refCon )
  469. {
  470.     // Nuke all previous stack crawls:
  471.     long flags;
  472.     StackCrawl *s = MMGetBlockStackCrawl(blk,&flags);
  473.     if( s ) {
  474.         delete s;
  475.         MMSetBlockStackCrawl(blk,NULL,0);
  476.     }
  477.     return kMMTrue;
  478. }
  479.  
  480.  
  481. void
  482. MMBeginLeakChecking( )
  483. {
  484.     somPrintf("••• Scanning for memory leaks: please do something 3 or more times.\r");
  485.     MMWalkHeap(NULL,(MMBlockInfoProc) &InitLeaksProc,NULL);
  486.     MMTrackStackCrawls(kMMTrue);
  487. }
  488.  
  489.  
  490. extern "C" {
  491. static MMBoolean FindLeaksProc(  const void *blk, size_t size, MMBoolean isObject,
  492.                                     void *refCon )
  493. {
  494.     long flags;
  495.     StackCrawl *s = MMGetBlockStackCrawl(blk,&flags);
  496.     if( s ) {
  497.         // This is a new block, check its stack crawl:
  498.         LeakLink *l;
  499.         for( l=sLeakLinks; l; l=l->fNext )
  500.             if( *(l->fStack) == *s ) {
  501.                 l->fCount++;
  502.                 delete s;
  503.                 MMSetBlockStackCrawl(blk,NULL,0);
  504.                 return kMMTrue;
  505.             }
  506.         l = new LeakLink;
  507.         l->fNext = sLeakLinks;
  508.         l->fFirstBlock = blk;
  509.         l->fStack = s;
  510.         l->fCount = 1;
  511.         sLeakLinks = l;
  512.     }
  513.     return kMMTrue;
  514. }
  515. }
  516.  
  517. static MMBoolean DumpObjProc(  const void *blk, size_t size, MMBoolean isObject,
  518.                                 void *dumpStack )
  519. {
  520.     if( isObject ) {
  521.         MMValidateObject((SOMObject*)blk);
  522.         somPrintf("  %p %4lu  %s\r", blk,size, ((SOMObject*)blk)->somGetClassName());
  523.     } else if( dumpStack )
  524.         somPrintf("  %p %4lu\r", blk,size);
  525.     if( dumpStack ) {
  526.         StackCrawl *s = MMGetBlockStackCrawl(blk,NULL);
  527.         if( s ) {
  528.             for( long i=0; i<s->CountFrames(); i++ ) {
  529.                 char name[256];
  530.                 s->GetFrameName(i,name);
  531.                 somPrintf("        %s\n",name);
  532.             }
  533.         }
  534.     }
  535.     return true;        // Might check for cmd-period or something to abort...
  536. }
  537.  
  538. void
  539. MMEndLeakChecking( )
  540. {
  541.     MMTrackStackCrawls(kMMFalse);
  542.     
  543.     somPrintf("••• Dumping memory leaks:\r");
  544.     sLeakLinks = NULL;
  545.     MMWalkHeap(NULL,&FindLeaksProc,NULL);
  546.     size_t leakage = 0;
  547.     LeakLink *next;
  548.     for( LeakLink *l=sLeakLinks; l; l=next ) {
  549.         next = l->fNext;
  550.         if( l->fCount >= 3 ) {
  551.             somPrintf("• Leaked %d times:\r", l->fCount);
  552.             size_t size = MMBlockSize(l->fFirstBlock);
  553.             DumpObjProc(l->fFirstBlock,
  554.                         size,
  555.                         MMIsObject(l->fFirstBlock),
  556.                         (void*)kMMTrue);
  557.             leakage += l->fCount * (size+8);    // Add 8 bytes for per-block overhead
  558.         }
  559.         delete l->fStack;
  560.         MMSetBlockStackCrawl(l->fFirstBlock,NULL,0);
  561.         delete l;
  562.     }
  563.     sLeakLinks = NULL;
  564.     if( leakage > 0 )
  565.         somPrintf("••• Estimated leakage: %ld bytes\r", leakage);
  566.     else
  567.         somPrintf("••• No leaks found!\r");
  568. }
  569.  
  570.  
  571. //========================================================================================
  572. // Non-Debug Stubs
  573. //========================================================================================
  574.  
  575. #else /* MM_DEBUG */
  576.  
  577.  
  578. void        MMBeginMemValidation( ) { }
  579. void        MMEndMemValidation( ) { }
  580. void        MMBeginHeapChecking( ) { }
  581. void        MMEndHeapChecking( ) { }
  582.  
  583. MMBoolean    MMValidatePtr( ConstMMBlock, MMBoolean validateHeap, const char *operation )
  584.                                                     {return 1;}
  585. MMBoolean    MMValidateObject( const SOMObject *o ) {return 1;}
  586. MMBoolean    MMValidateHandle( MMHandle ) {return 1;}
  587.  
  588. MMBoolean    MMDoesHeapExist( MemHeap *heap ) {return 1;}
  589. MMBoolean    MMValidateHeap( MemHeap *heapID, const void* ptr ) {return 1;}
  590. MMBoolean    MMValidateAllHeaps( ) {return 1;}
  591.  
  592. void        MMGetHeapInfo( MemHeap *heapID,
  593.                             const char* *name, size_t *allocated, size_t *free,
  594.                             size_t *nBlocks, size_t *nObjects ) { }
  595.  
  596. void        MMWalkHeap( MemHeap *heapID, MMBlockInfoProc, void *StackCrawl )  { }
  597.  
  598. MMBoolean    MMFindBlockContaining( const void *, const void*,
  599.                                     const void* *blockStart, const void* *blockEnd )
  600. {
  601.     if( blockStart ) *blockStart=NULL;
  602.     return 0;
  603. }
  604. MMBoolean    MMValidateMemoryRange( const void *start, const void *end )    {return 1;}
  605.  
  606. MMBoolean    MMTrackStackCrawls( MMBoolean ) {return 0;}
  607. StackCrawl* MMGetBlockStackCrawl( const void *block, long *flags )
  608.     {if( flags ) *flags = 0; return NULL;}
  609. void MMSetBlockStackCrawl( const void *block, StackCrawl*, long flags ) { }
  610.  
  611. void        MMBeginLeakChecking( void )    { }
  612. void        MMEndLeakChecking( void ) { }
  613.  
  614.  
  615.  
  616. #endif /*MMDebug*/
  617.