home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #19 / NN_1992_19.iso / spool / comp / sys / mac / programm / 14630 < prev    next >
Encoding:
Text File  |  1992-08-27  |  10.6 KB  |  397 lines

  1. Newsgroups: comp.sys.mac.programmer
  2. Path: sparky!uunet!decwrl!adobe!jholt@adobe.com
  3. From: jholt@adobe.com (joe holt)
  4. Subject: Re: Looping through all allocated blocks
  5. Message-ID: <1992Aug27.222559.17208@adobe.com>
  6. Sender: usenet@adobe.com (USENET NEWS)
  7. Organization: Adobe Systems Inc.
  8. References: <17envmINNgab@function.mps.ohio-state.edu>
  9. Date: Thu, 27 Aug 1992 22:25:59 GMT
  10. Lines: 385
  11.  
  12. In article <17envmINNgab@function.mps.ohio-state.edu>, gregt@function.mps.ohio-state.edu (Gregory M Ferrar) writes:
  13. > I'm writing a program in THINK C, and I would really like to know how to
  14. > examine each memory block in order.  In other words, I would like some sort
  15. > of loop which allows me to process all handles or pointers which have been
  16. > allocated since the start of the program.  How can this be done?
  17. >   -Greg Ferrar (gregt@function.mps.ohio-state.edu)
  18.  
  19. Greg,
  20.  
  21. Here's a small package I wrote for checking the consistency of a Macintosh
  22. heap. It's similar to the routines in Swatch which build its memory bars (if
  23. you've ever seen Swatch...). In broad terms, it shows how to walk a heap.
  24. I hope this helps.
  25.  
  26. Written with THINK C 5.0.2.
  27.  
  28. /joe
  29.  
  30. ---------- Heap_validate.h ----------
  31.  
  32. /**
  33.  
  34.     Heap_validate.h
  35.     Check heap for consistency.
  36.  
  37.  **/
  38.  
  39. #ifndef __Heap_validate__
  40. #define __Heap_validate__
  41.  
  42.  
  43. /*    Errors returned by Heap_validate_info() about last Heap_validate() call. */
  44.  
  45. enum {
  46.     Heap_validate_okay = 0,
  47.     Heap_validate_zone_bad,                        /* bad zone address */
  48.     Heap_validate_zone_header_bad,                /* zone's bkLim not valid */
  49.     Heap_validate_block_size_bad,                /* size is negative or way too big */
  50.     Heap_validate_block_relative_handle_bad,    /* doesn't point where it should */
  51.     Heap_validate_block_type_bad,                /* not a defined type */
  52.     Heap_validate_master_pointer_bad            /* circle not consistent */
  53. };
  54.  
  55.  
  56. Boolean Heap_validate( THz zone );
  57.  
  58. /*    Validate the given heap. Returns true if the heap is consistent, false if
  59.     there's a problem. For example:
  60.  
  61.         Heap_validate( ApplicZone() );    -- validate the current application
  62.         Heap_validate( SystemZone() );    -- validate the system heap
  63.  
  64.     When Heap_validate returns false, call Heap_validate_info() for information
  65.     about the nature of the inconsistency. */
  66.  
  67.  
  68. void Heap_validate_info( short *error, Ptr *block );
  69.  
  70. /*    Return information about the nature of a heap inconsistency. If Heap_validate()
  71.     says the heap is bad, Heap_validate_info() will point to the bad block and tell
  72.     you why it is bad. Note that any inconsistency renders the heap unusable.
  73.  
  74.     Much heap debugging can be done without calling Heap_validate_info(). However, you
  75.     may want to use this function to help zero in on the cause of the inconsistency.
  76.  
  77.     For example, if block A is bad with an error indicating that its header is
  78.     clobbered (errors Heap_validate_block_size_bad, Heap_validate_block_type_bad or
  79.     Heap_validate_block_relative_handle_bad), the cause may be that you wrote past
  80.     the end of block A-1.
  81.  
  82.     Pass nil for error or block if you're not interested in the value. */
  83.  
  84. #endif
  85.  
  86. ---------- end of Heap_validate.h ----------
  87.  
  88. ---------- Heap_validate.c ----------
  89.  
  90. /**
  91.  
  92.     Heap_validate.c
  93.     Check heap for consistency.
  94.  
  95.     version 1.0
  96.     23 March 1992, joe holt
  97.  
  98.  **/
  99.  
  100.  
  101. /**-----------------------------------------------------------------------------
  102.  **
  103.  **    Headers
  104.  **
  105.  **/
  106.  
  107. #include <GestaltEqu.h>        /* for querying about 24- and 32-bit addressing */
  108. #include "Heap_validate.h"
  109.  
  110.  
  111. /**-----------------------------------------------------------------------------
  112.  **
  113.  ** Private Variables
  114.  **
  115.  **/
  116.  
  117. /*    24-bit Memory Manager block header structure. Stored in the eight bytes
  118.     preceding a heap block. See IM 2-23. */
  119.  
  120. typedef struct {
  121.     long tag_and_size;        /* block type, size alignment, and physical size */
  122.     long relative_handle;    /* pointer to master pointer */
  123. } block_header_24_t;
  124.  
  125. /*    Physical size includes header size and size correction bytes at end of block.
  126.     In other words, adding the physical size of block A to address of A gives
  127.     the address of block A+1. */
  128.  
  129. /*    Relative handle is a pointer back to the block's master pointer if the block
  130.     is relocatable. It is "relative" because it is expressed as an offset into
  131.     the heap. That is, adding the relative handle of block A to the base address
  132.     of the heap gives the address of block A's master pointer.
  133.  
  134.     If the block is nonrelocatable, the relative handle field contains the base
  135.     address of the heap. The relative handles of all nonrelocatable blocks in
  136.     the same heap contain the same value. */
  137.  
  138. /*    Size alignment is the extra "slop" bytes at the end of a block. They are
  139.     not part of the logical block. See IM 2-24 for an explanation of why they
  140.     exist. */
  141.  
  142. #define BLOCK_HEADER_24_SIZE_MASK     0x00FFFFFF
  143. #define BLOCK_HEADER_24_TYPE_MASK     0xC0
  144.  
  145.  
  146. /*    32-bit Memory Manager block header structure. Stored in the twelve bytes
  147.     preceding a heap block. */
  148.  
  149. typedef struct {
  150.     unsigned char type;        /* block type; see below */
  151.     unsigned char flags;    /* block flags; see below */
  152.     short alignment;        /* physical size alignment */
  153.     long size;                /* physical size; same definition as above */
  154.     long relative_handle;    /* same definition as above */
  155. } block_header_32_t;
  156.  
  157.  
  158. /*    Block type constants. Contained in upper byte of tag_and_size field for
  159.     24-bit heaps and in the type field for 32-bit heaps. */
  160.  
  161. #define FREE_TYPE            0x00
  162. #define NONREL_TYPE            0x40
  163. #define HANDLE_TYPE            0x80
  164.  
  165.  
  166. /*    Block flags constants. Contained in the upper byte of the master pointer
  167.     for 24-bit heaps and in the flags field for 32-bit heaps. Defined only
  168.     for relocatable blocks. */
  169.  
  170. #define LOCK_FLAG_MASK        0x80
  171. #define PURGE_FLAG_MASK        0x40
  172. #define RESOURCE_FLAG_MASK    0x20
  173.  
  174. #define MASTER_POINTER_24_ADDRESS_MASK    0x00FFFFFF
  175.  
  176.  
  177. static Boolean heap_addressing_known = false;
  178. static Boolean system_heap_is_32_bit, process_heaps_are_32_bit;
  179.  
  180. static short validate_error;
  181. static void *validate_block;
  182.  
  183.  
  184. /**-----------------------------------------------------------------------------
  185.  **
  186.  ** Private Functions
  187.  **
  188.  **/
  189.  
  190. /*    Determine the Memory Manager addressing mode for the System heap and for
  191.     process (application) heaps. Gestalt Manager documentation suggests that
  192.     they may not necessarily be the same. */
  193.  
  194. static void get_heap_addressing( void );
  195. static void get_heap_addressing( void )
  196. {
  197.     long response;
  198.  
  199.     if ( Gestalt( gestaltAddressingModeAttr, &response ) )
  200.         DebugStr( "\p get_heap_addressing(): Gestalt call failed" );
  201.  
  202.     system_heap_is_32_bit = (response & (1<<gestalt32BitSysZone)) != 0;
  203.     process_heaps_are_32_bit = (response & (1<<gestalt32BitAddressing)) != 0;
  204.  
  205.     heap_addressing_known = true;
  206. }
  207.  
  208.  
  209. /*******************************************************************************
  210.  **
  211.  **    Public Functions
  212.  **
  213.  **/
  214.  
  215. /*    Validate the given heap. Returns true if the heap is consistent, false if
  216.     there's a problem. For example:
  217.  
  218.         Heap_validate( ApplicZone() );    -- validate the current application
  219.         Heap_validate( SystemZone() );    -- validate the system heap
  220.  
  221.     When Heap_validate returns false, call Heap_validate_info() for information
  222.     about the nature of the inconsistency. */
  223.  
  224. Boolean Heap_validate( THz zone )
  225. {
  226.     Ptr bh, bkLim;
  227.     long size;
  228.     unsigned char type;
  229.     short error;
  230.  
  231.     validate_block = nil;
  232.  
  233.     if ( (Ptr) zone < (Ptr) SysZone || (long) zone & 1 ) {
  234.         error = Heap_validate_zone_bad;
  235.         goto out;
  236.     }
  237.  
  238.     bh = (Ptr) &zone->heapData;
  239.     bkLim = zone->bkLim;
  240.  
  241.     if ( bkLim < bh || (long) bkLim & 1 ) {
  242.         error = Heap_validate_zone_header_bad;
  243.         goto out;
  244.     }
  245.  
  246.  
  247.     if ( !heap_addressing_known ) get_heap_addressing();
  248.  
  249.     if ( (zone == SysZone && system_heap_is_32_bit) || process_heaps_are_32_bit ) {
  250.  
  251.         for ( ;; ) {
  252.  
  253.             if ( bh > bkLim || ((long) bh & 1) ) {
  254.                 error = Heap_validate_block_size_bad;
  255.                 break;
  256.             }
  257.  
  258.             if ( bh == bkLim ) {
  259.                 error = Heap_validate_okay;
  260.                 validate_block = nil;
  261.                 break;        // reached the end w/o problems
  262.             }
  263.  
  264.  
  265.             validate_block = bh + 12;    /* block logical address */
  266.  
  267.             size = ((block_header_32_t *)bh)->size;
  268.             if ( bh + size <= bh ) {
  269.                 error = Heap_validate_block_size_bad;
  270.                 break;
  271.             }
  272.  
  273.             type = ((block_header_32_t *)bh)->type;
  274.  
  275.             if ( type == NONREL_TYPE ) {
  276.                 if ( ((block_header_32_t *)bh)->relative_handle != (long) zone ) {
  277.                     error = Heap_validate_block_relative_handle_bad;
  278.                     break;
  279.                 }
  280.             }
  281.  
  282.             else if ( type == HANDLE_TYPE ) {
  283.  
  284.                 Ptr tp = (Ptr) zone + ((block_header_32_t *)bh)->relative_handle;
  285.  
  286.                 if ( tp > bkLim || ((long) tp & 1) ) {
  287.                     error = Heap_validate_block_relative_handle_bad;
  288.                     break;
  289.                 }
  290.  
  291.                 if ( *(Ptr *)tp != bh + 12 /* points to contents */ ) {
  292.                     error = Heap_validate_master_pointer_bad;
  293.                     break;
  294.                 }
  295.  
  296.             }
  297.  
  298.             else if ( type != FREE_TYPE ) {
  299.                 error = Heap_validate_block_type_bad;
  300.                 break;
  301.             }
  302.  
  303.  
  304.             bh += size;
  305.  
  306.         }
  307.     }
  308.     else {
  309.  
  310.         for ( ;; ) {
  311.  
  312.             if ( bh > bkLim || ((long) bh & 1) ) {
  313.                 error = Heap_validate_block_size_bad;
  314.                 break;
  315.             }
  316.  
  317.             if ( bh == bkLim ) {
  318.                 error = Heap_validate_okay;
  319.                 validate_block = nil;
  320.                 break;        // reached the end w/o problems
  321.             }
  322.  
  323.             validate_block = bh + 8;    /* block logical address */
  324.  
  325.             size = ((block_header_24_t *)bh)->tag_and_size & BLOCK_HEADER_24_SIZE_MASK;
  326.             if ( bh + size <= bh ) {
  327.                 error = Heap_validate_block_size_bad;
  328.                 break;
  329.             }
  330.  
  331.             type = (((block_header_24_t *)bh)->tag_and_size >> 24) &
  332.                     BLOCK_HEADER_24_TYPE_MASK;
  333.  
  334.             if ( type == NONREL_TYPE ) {
  335.                 if ( ((block_header_24_t *)bh)->relative_handle != (long) zone ) {
  336.                     error = Heap_validate_block_relative_handle_bad;
  337.                     break;
  338.                 }
  339.             }
  340.  
  341.             else if ( type == HANDLE_TYPE ) {
  342.  
  343.                 Ptr tp = (Ptr) zone + ((block_header_24_t *)bh)->relative_handle;
  344.  
  345.                 if ( tp > bkLim || ((long) tp & 1) ) {
  346.                     error = Heap_validate_block_relative_handle_bad;
  347.                     break;
  348.                 }
  349.  
  350.                 if ( (*(long *)tp & MASTER_POINTER_24_ADDRESS_MASK) != (long) bh + 8 ) {
  351.                     error = Heap_validate_master_pointer_bad;
  352.                     break;
  353.                 }
  354.             }
  355.  
  356.             else if ( type != FREE_TYPE ) {
  357.                 error = Heap_validate_block_type_bad;
  358.                 break;
  359.             }
  360.  
  361.  
  362.             bh += size;
  363.  
  364.         }
  365.     }
  366.  
  367. out:
  368.     validate_error = error;
  369.     return error == Heap_validate_okay;
  370. }
  371.  
  372.  
  373. /*    Return information about the nature of a heap inconsistency. If Heap_validate()
  374.     says the heap is bad, Heap_validate_info() will point to the bad block and tell
  375.     you why it is bad. Note that any inconsistency renders the heap unusable.
  376.  
  377.     Much heap debugging can be done without calling Heap_validate_info(). However, you
  378.     may want to use this function to help zero in on the cause of the inconsistency.
  379.  
  380.     For example, if block A is bad with an error indicating that its header is
  381.     clobbered (errors Heap_validate_block_size_bad, Heap_validate_block_type_bad or
  382.     Heap_validate_block_relative_handle_bad), the cause may be that you wrote past
  383.     the end of block A-1.
  384.  
  385.     Pass nil for error or block if you're not interested in the value. */
  386.  
  387. void Heap_validate_info( short *error, Ptr *block )
  388. {
  389.     if ( error ) *error = validate_error;
  390.     if ( block ) *block = validate_block;
  391. }
  392.  
  393.