home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / memory / heapdbg / heap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-12  |  11.9 KB  |  406 lines

  1. /*********************************HEAP.C*****************************************/
  2.  
  3. /*
  4.  * Author:       Mark Nelson
  5.  *
  6.  * Date:         October 28, 1989
  7.  *
  8.  * Description:  This module contains the replacement routines used
  9.  *               to debug heap problems.  The routines are used in
  10.  *               conjunction with the HEAP.H header file.
  11.  */
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <stdarg.h>
  15. #include <malloc.h>
  16. #include <conio.h>
  17. #include "_heap.h"
  18.  
  19. /*
  20.  * This structure defines all the fields that I use in the tag
  21.  * table database.
  22.  */
  23. #define TAG_MAX 100
  24.  
  25. struct tags {
  26.                 char far * returned_address;
  27.                 char far * real_address;
  28.                 size_t size;
  29.                 char *file_name;
  30.                 unsigned int line_number;
  31.                 char maverick;
  32.                 char tagged;
  33.             } tag_table[TAG_MAX];
  34.  
  35. int next_free_tag = -1;
  36.  
  37.  
  38. /*
  39.  * These are some odds and ends I use all around.
  40.  */
  41. char leading_picket[] = "0123456789ABCDE";
  42. char trailing_picket[] = "FEDCBA987654321";
  43. #define PICKET_SIZE sizeof( leading_picket )
  44.  
  45.  
  46. /*
  47.  * These are the labels and widths for each of the columns in the output
  48.  * screen.
  49.  */
  50. char *labels[]={"Tag #","File Name","Line #","Picket","Address","Size","Picket",""};
  51. int widths[]={5,12,6,15,9,6,15};
  52. extern int columns[];
  53. int screen_up=0;
  54. int message_line;
  55.  
  56.  
  57. /*
  58.  * This is the my_malloc routine that replaces malloc().  Before it does
  59.  * anything else, it performs the heap checkout stuff.  This will pop up
  60.  * a message if anything funny is detected.  It then gets the pointer
  61.  * for the caller, and adds it to the tag table.  The screen is then
  62.  * cleared up, and the pointer is returned.
  63.  */
  64.  
  65. void *my_malloc(char *file_name,unsigned int line_number,size_t size)
  66. {
  67.   void *malloc_pointer;
  68.   size_t real_size;
  69.  
  70.   verify_heap();
  71.   real_size = size + PICKET_SIZE*2;
  72.   malloc_pointer = malloc( real_size );
  73.   if ( malloc_pointer == NULL ) {
  74.     screen_message( 1, 0, "File: %s Line: %u requesting %u bytes",
  75.                     file_name, line_number, size );
  76.     screen_message( 0, 0, "Malloc failed! Null pointer will be returned." );
  77.   }
  78.   else
  79.     add_tag_to_table( malloc_pointer, 0, size, file_name, line_number );
  80.   hide_screen();
  81.   return( ( char * ) malloc_pointer + PICKET_SIZE );
  82. }
  83.  
  84.  
  85. /*
  86.  * my_free is set up to replace free().  Just like my_malloc(), it first
  87.  * checks out the heap and prints a message if anything funny shows up.
  88.  * Before I try to free the block, I have to check and see if it is in
  89.  * my tag table.  If it is, I free the real pointer, not the one I passed
  90.  * back to the caller.  If it isn't in the tag table, I print a message
  91.  * out to that effect, and return.
  92.  */
  93.  
  94. void my_free( char *file_name, unsigned int line_number, void *block )
  95. {
  96.   int tag;
  97.  
  98.   verify_heap();
  99.   for ( tag = 0; tag < TAG_MAX ; tag++ ) {
  100.     if ( tag_table[ tag ].returned_address == ( void far * ) block )
  101.       break;
  102.   }
  103.   if ( tag < TAG_MAX ) {
  104.     if ( tag_table[ tag ].maverick ) {
  105.         screen_message( 1, 0, "File: %s Line: %u freeing block %Fp",
  106.                         file_name, line_number, ( void far * ) block );
  107.         screen_message( 0, 0, "Tag is a maverick entry!" );
  108.         free( block );
  109.     }
  110.     else
  111.         free( ( char * ) block - PICKET_SIZE );
  112.     delete_tag_from_table( tag );
  113.   }
  114.   else {
  115.     screen_message( 1, 0, "File: %s Line: %u freeing block %Fp",
  116.                     file_name, line_number, ( void far * ) block );
  117.     screen_message( 0, 0, "Tag was not found in tag table!  Going to try and free() it." );
  118.     free( block );
  119.     screen_message( 0, 0, "Heap after freeing anonymous block!" );
  120.   }
  121.   hide_screen();
  122. }
  123.  
  124.  
  125. /*
  126.  * I need to initialize the tag table my first time through.  This
  127.  * routine gets called all the time, but only performs the initialization
  128.  * once, when next_free_tag is -1.
  129.  */
  130.  
  131. void initialize_tags()
  132. {
  133.   int i;
  134.  
  135.   if ( next_free_tag == -1 ) {
  136.     next_free_tag = 0;
  137.     for ( i = 0 ; i < TAG_MAX ; i++ ) {
  138.       tag_table[ i ].returned_address = NULL;
  139.       tag_table[ i ].file_name = "Not in use";
  140.       tag_table[ i ].line_number = 0;
  141.       tag_table[ i ].size = 0;
  142.     }
  143.   }
  144. }
  145.  
  146.  
  147. /*
  148.  * This is the routine called to display the tag table when something
  149.  * has gone wrong.  It sits in a loop displaying tag table entries, 15
  150.  * at a time.  The user can hit the 'u' or 'd' keys to move up or down
  151.  * in the table.  Any other key breaks the user out.
  152.  */
  153.  
  154. void display_tag_table( int last_tag )
  155. {
  156.   int first_tag;
  157.   int offset;
  158.   int tag;
  159.   char far *picket_pointer;
  160.   int key;
  161.  
  162.   if ( last_tag < 16 )
  163.     first_tag = 0;
  164.   else
  165.     first_tag = last_tag - 15;
  166.  
  167.     for ( ; ; ) {
  168.     for ( offset = 0 ; offset < 15 ; offset++ ) {
  169.       tag = first_tag + offset;
  170.       screenputf( offset + 3, columns[ 0 ] + 1, "%-3d", tag );
  171.       screenputf( offset + 3, columns[ 1 ] + 1, "%-12s",
  172.                   tag_table[ tag ].file_name );
  173.       screenputf( offset + 3, columns[ 2 ] + 1, "%-5d",
  174.                   tag_table[ tag ].line_number );
  175.       if ( tag_table[ tag ].returned_address != NULL ) {
  176.         picket_pointer = tag_table[ tag ].returned_address;
  177.         picket_pointer -= PICKET_SIZE ;
  178.         if ( tag_table[ tag ].maverick )
  179.           screenputf( offset + 3, columns[ 3 ] + 1,"%15s", "***MAVERICK***" );
  180.         else
  181.           screenputf( offset + 3, columns[ 3 ] + 1, "%15s", picket_pointer );
  182.         screenputf( offset + 3, columns[ 4 ] + 1, "%Fp",
  183.                     tag_table[ tag ].returned_address );
  184.         picket_pointer += PICKET_SIZE;
  185.         picket_pointer += tag_table[ tag ].size;
  186.         if ( tag_table[ tag ].maverick )
  187.           screenputf( offset + 3, columns[ 6 ] + 1, "%15s", "***MAVERICK***" );
  188.         else
  189.           screenputf( offset + 3, columns[ 6 ] + 1, "%15s", picket_pointer );
  190.       }
  191.       else {
  192.         screenputf( offset + 3, columns[ 3 ] + 1, "%15s", "" );
  193.         screenputf( offset + 3, columns[ 4 ] + 1, "  NULL   " );
  194.         screenputf( offset + 3, columns[ 6 ] + 1, "%15s", "" );
  195.       }
  196.       screenputf( offset + 3, columns[ 5 ] + 1, "%-5d", tag_table[ tag ].size );
  197.     }
  198.     key = getch();
  199.     if ( key == 'u' || key == 'U' ) {
  200.         first_tag -= 15;
  201.         if (first_tag < 0)
  202.           first_tag = 0;
  203.     }
  204.     else if ( key == 'd' || key == 'D' ) {
  205.       first_tag += 15;
  206.       if ( ( first_tag + 15 ) >= TAG_MAX )
  207.         first_tag = TAG_MAX - 15;
  208.     }
  209.     else
  210.       break;
  211.   }
  212. }
  213.  
  214.  
  215. /*
  216.  * This routine is called when a new pointer needs to be added to the tag
  217.  * table.  It can be a maverick pointer or a regular pointer.
  218.  */
  219.  
  220. void add_tag_to_table( char far *pointer,
  221.                        char maverick,
  222.                        size_t size,
  223.                        char *file_name,
  224.                        unsigned int line_number )
  225. {
  226.   int i;
  227.  
  228.   if ( next_free_tag >= TAG_MAX )
  229.     return;
  230.   tag_table[ next_free_tag ].returned_address = pointer;
  231.   tag_table[ next_free_tag ].real_address = pointer;
  232.   tag_table[ next_free_tag ].size = size;
  233.   tag_table[ next_free_tag ].file_name = file_name;
  234.   tag_table[ next_free_tag ].line_number = line_number;
  235.   tag_table[ next_free_tag ].maverick = maverick;
  236.   if ( !maverick ) {
  237.     for ( i = 0 ; i < PICKET_SIZE ; i++ )
  238.       pointer[ i ] = leading_picket[ i ];
  239.     pointer += size;
  240.     pointer += PICKET_SIZE ;
  241.     for ( i = 0 ; i < PICKET_SIZE ; i++ )
  242.       pointer[ i ] = trailing_picket[ i ];
  243.     tag_table[ next_free_tag ].returned_address += PICKET_SIZE;
  244.   }
  245.   next_free_tag++;
  246. }
  247.  
  248.  
  249. /*
  250.  * This routine is called when a tag needs to be deleted from the table.  This
  251.  * can happen when a call to free() is made, or when a heapwalk shows that
  252.  * one of the pointers is missing.
  253.  */
  254.  
  255. void delete_tag_from_table( int tag )
  256. {
  257.   int i;
  258.  
  259.   next_free_tag--;
  260.   for ( i = tag ; i < next_free_tag ; i++ )
  261.     tag_table[ i ] = tag_table[ i + 1 ];
  262.   tag_table[ i ].returned_address = NULL;
  263.   tag_table[ i ].file_name = "Not in use";
  264.   tag_table[ i ].line_number = 0;
  265.   tag_table[ i ].size = 0;
  266. }
  267.  
  268.  
  269. /*
  270.  *  This is the verify routine that is called on the entry to my_malloc()
  271.  *  or my_free().  It calls the heap_walk() routine first, to let it do
  272.  *  its check out of the heap.  It then goes through the entire tag table
  273.  *  and verifies that the pickets are all intact.
  274.  */
  275.  
  276. void verify_heap()
  277. {
  278.   int i;
  279.   int tag;
  280.   char far *picket_pointer;
  281.  
  282.   initialize_tags();
  283.   heap_walk();
  284.   for ( tag = 0 ; tag < next_free_tag ; tag++ ) {
  285.     if ( tag_table[ tag ].maverick )
  286.       continue;
  287.     picket_pointer = tag_table[ tag ].returned_address;
  288.     picket_pointer -= PICKET_SIZE ;
  289.     for ( i = 0 ; i < PICKET_SIZE ; i++ )
  290.       if ( picket_pointer[ i ] != leading_picket[ i ] ) {
  291.         screen_message( 0, i, "Error in leading picket, tag %3d", tag );
  292.         break;
  293.       }
  294.     picket_pointer += PICKET_SIZE ;
  295.     picket_pointer += tag_table[tag].size;
  296.     for ( i = 0 ; i < PICKET_SIZE ; i++ )
  297.       if ( picket_pointer[ i ] != trailing_picket[ i ] ) {
  298.         screen_message( 0, tag, "Error in trailing picket, tag %3d", tag );
  299.         break;
  300.       }
  301.   }
  302. }
  303.  
  304. /*
  305.  * This is the routine that walks through the heap.  If an heap entry
  306.  * is not found in the tag table, a message is printed, and it is added
  307.  * as a maverick.  Otherwise, the tag is noted.  After walking through
  308.  * the whole heap, a check is done to see if any of our tagged entries
  309.  * didn't show up, which generates another message.
  310.  *
  311.  * Remember that this code is MSC-specific.  You need to rewrite this
  312.  * routine for every different compiler.
  313.  */
  314.  
  315. void heap_walk()
  316. {
  317.   struct _heapinfo hinfo;
  318.   int heapstatus;
  319.   size_t size;
  320.   int i;
  321.  
  322.   hinfo._pentry = NULL;
  323.  
  324.   for ( i = 0 ; i < next_free_tag ; i++ )
  325.     tag_table[ i ].tagged = 0;
  326.  
  327.   for ( ; ; ) {
  328.     heapstatus = _heapwalk( &hinfo );
  329.     if ( heapstatus == _HEAPEMPTY )
  330.       break;
  331.     if ( heapstatus == _HEAPEND )
  332.       break;
  333.     if ( heapstatus != _HEAPOK ) {
  334.       screen_message( 0, 0, "Heap is corrupted! Going to exit." );
  335.       exit( 1 );
  336.     }
  337.     if ( hinfo._useflag != _USEDENTRY )
  338.       continue;
  339.     for ( i = 0 ; i < next_free_tag ; i++ ) {
  340.       if ( (int far *) tag_table[ i ].real_address == hinfo._pentry ) {
  341.         tag_table[ i ].tagged = 1;
  342.         break;
  343.       }
  344.     }
  345.     if ( i == next_free_tag ) {
  346.       size = hinfo._size;
  347.       if ( i < TAG_MAX )
  348.         tag_table[ i ].tagged = 1;
  349.       add_tag_to_table( (char far *) hinfo._pentry, 1, size, "MAVERICK",0 );
  350.       screen_message( 0, i, "Found a maverick heap entry: %Fp", hinfo._pentry );
  351.     }
  352.   }
  353. /*
  354.  * At this point every entry should have been tagged, so I can go through
  355.  * the table and look for ones that didn't get tagged.
  356.  */
  357.   for ( i = 0 ; i < next_free_tag ; i++ ) {
  358.     if ( tag_table[ i ].tagged == 0 ) {
  359.       screen_message( 0, i, "Didn't find heap entry in heapwalk, tag %d", i );
  360.       delete_tag_from_table( i );
  361.     }
  362.   }
  363. }
  364.  
  365.  
  366. /*
  367.  * During the process of checking out the heap, if I see anything worthy
  368.  * of a message, I call this routine.  If the screen is not already up,
  369.  * this guy pulls it up.  Then it prints the message.
  370.  */
  371.  
  372. void screen_message( int immediate_return, int tag, char *format, ... )
  373. {
  374.   char message[ 81 ];
  375.   va_list args;
  376.  
  377.   if ( screen_up == 0 ) {
  378.     screen_up = 1;
  379.     message_line = 20;
  380.     setup_screen( labels, widths, 15 );
  381.   }
  382.   va_start( args, format );
  383.   vsprintf( message, format, args );
  384.   screenputs( message_line, 0, message );
  385.   if ( ++message_line >= 25 )
  386.     message_line = 20;
  387.   if ( !immediate_return )
  388.     display_tag_table( tag );
  389. }
  390.  
  391. /*
  392.  * After all the work is done, I have to hide my heap screen so the user
  393.  * can see the application output.  This is pretty easy to do, a routine
  394.  * in SCREEN.C does the whole job for me.
  395.  */
  396. void hide_screen()
  397. {
  398.   if ( screen_up != 0 ) {
  399.     screen_up = 0;
  400.     restore_screen();
  401.   }
  402. }
  403.  
  404.  
  405.  
  406.