home *** CD-ROM | disk | FTP | other *** search
- /*********************************HEAP.C*****************************************/
-
- /*
- * Author: Mark Nelson
- *
- * Date: October 28, 1989
- *
- * Description: This module contains the replacement routines used
- * to debug heap problems. The routines are used in
- * conjunction with the HEAP.H header file.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <malloc.h>
- #include <conio.h>
- #include "_heap.h"
-
- /*
- * This structure defines all the fields that I use in the tag
- * table database.
- */
- #define TAG_MAX 100
-
- struct tags {
- char far * returned_address;
- char far * real_address;
- size_t size;
- char *file_name;
- unsigned int line_number;
- char maverick;
- char tagged;
- } tag_table[TAG_MAX];
-
- int next_free_tag = -1;
-
-
- /*
- * These are some odds and ends I use all around.
- */
- char leading_picket[] = "0123456789ABCDE";
- char trailing_picket[] = "FEDCBA987654321";
- #define PICKET_SIZE sizeof( leading_picket )
-
-
- /*
- * These are the labels and widths for each of the columns in the output
- * screen.
- */
- char *labels[]={"Tag #","File Name","Line #","Picket","Address","Size","Picket",""};
- int widths[]={5,12,6,15,9,6,15};
- extern int columns[];
- int screen_up=0;
- int message_line;
-
-
- /*
- * This is the my_malloc routine that replaces malloc(). Before it does
- * anything else, it performs the heap checkout stuff. This will pop up
- * a message if anything funny is detected. It then gets the pointer
- * for the caller, and adds it to the tag table. The screen is then
- * cleared up, and the pointer is returned.
- */
-
- void *my_malloc(char *file_name,unsigned int line_number,size_t size)
- {
- void *malloc_pointer;
- size_t real_size;
-
- verify_heap();
- real_size = size + PICKET_SIZE*2;
- malloc_pointer = malloc( real_size );
- if ( malloc_pointer == NULL ) {
- screen_message( 1, 0, "File: %s Line: %u requesting %u bytes",
- file_name, line_number, size );
- screen_message( 0, 0, "Malloc failed! Null pointer will be returned." );
- }
- else
- add_tag_to_table( malloc_pointer, 0, size, file_name, line_number );
- hide_screen();
- return( ( char * ) malloc_pointer + PICKET_SIZE );
- }
-
-
- /*
- * my_free is set up to replace free(). Just like my_malloc(), it first
- * checks out the heap and prints a message if anything funny shows up.
- * Before I try to free the block, I have to check and see if it is in
- * my tag table. If it is, I free the real pointer, not the one I passed
- * back to the caller. If it isn't in the tag table, I print a message
- * out to that effect, and return.
- */
-
- void my_free( char *file_name, unsigned int line_number, void *block )
- {
- int tag;
-
- verify_heap();
- for ( tag = 0; tag < TAG_MAX ; tag++ ) {
- if ( tag_table[ tag ].returned_address == ( void far * ) block )
- break;
- }
- if ( tag < TAG_MAX ) {
- if ( tag_table[ tag ].maverick ) {
- screen_message( 1, 0, "File: %s Line: %u freeing block %Fp",
- file_name, line_number, ( void far * ) block );
- screen_message( 0, 0, "Tag is a maverick entry!" );
- free( block );
- }
- else
- free( ( char * ) block - PICKET_SIZE );
- delete_tag_from_table( tag );
- }
- else {
- screen_message( 1, 0, "File: %s Line: %u freeing block %Fp",
- file_name, line_number, ( void far * ) block );
- screen_message( 0, 0, "Tag was not found in tag table! Going to try and free() it." );
- free( block );
- screen_message( 0, 0, "Heap after freeing anonymous block!" );
- }
- hide_screen();
- }
-
-
- /*
- * I need to initialize the tag table my first time through. This
- * routine gets called all the time, but only performs the initialization
- * once, when next_free_tag is -1.
- */
-
- void initialize_tags()
- {
- int i;
-
- if ( next_free_tag == -1 ) {
- next_free_tag = 0;
- for ( i = 0 ; i < TAG_MAX ; i++ ) {
- tag_table[ i ].returned_address = NULL;
- tag_table[ i ].file_name = "Not in use";
- tag_table[ i ].line_number = 0;
- tag_table[ i ].size = 0;
- }
- }
- }
-
-
- /*
- * This is the routine called to display the tag table when something
- * has gone wrong. It sits in a loop displaying tag table entries, 15
- * at a time. The user can hit the 'u' or 'd' keys to move up or down
- * in the table. Any other key breaks the user out.
- */
-
- void display_tag_table( int last_tag )
- {
- int first_tag;
- int offset;
- int tag;
- char far *picket_pointer;
- int key;
-
- if ( last_tag < 16 )
- first_tag = 0;
- else
- first_tag = last_tag - 15;
-
- for ( ; ; ) {
- for ( offset = 0 ; offset < 15 ; offset++ ) {
- tag = first_tag + offset;
- screenputf( offset + 3, columns[ 0 ] + 1, "%-3d", tag );
- screenputf( offset + 3, columns[ 1 ] + 1, "%-12s",
- tag_table[ tag ].file_name );
- screenputf( offset + 3, columns[ 2 ] + 1, "%-5d",
- tag_table[ tag ].line_number );
- if ( tag_table[ tag ].returned_address != NULL ) {
- picket_pointer = tag_table[ tag ].returned_address;
- picket_pointer -= PICKET_SIZE ;
- if ( tag_table[ tag ].maverick )
- screenputf( offset + 3, columns[ 3 ] + 1,"%15s", "***MAVERICK***" );
- else
- screenputf( offset + 3, columns[ 3 ] + 1, "%15s", picket_pointer );
- screenputf( offset + 3, columns[ 4 ] + 1, "%Fp",
- tag_table[ tag ].returned_address );
- picket_pointer += PICKET_SIZE;
- picket_pointer += tag_table[ tag ].size;
- if ( tag_table[ tag ].maverick )
- screenputf( offset + 3, columns[ 6 ] + 1, "%15s", "***MAVERICK***" );
- else
- screenputf( offset + 3, columns[ 6 ] + 1, "%15s", picket_pointer );
- }
- else {
- screenputf( offset + 3, columns[ 3 ] + 1, "%15s", "" );
- screenputf( offset + 3, columns[ 4 ] + 1, " NULL " );
- screenputf( offset + 3, columns[ 6 ] + 1, "%15s", "" );
- }
- screenputf( offset + 3, columns[ 5 ] + 1, "%-5d", tag_table[ tag ].size );
- }
- key = getch();
- if ( key == 'u' || key == 'U' ) {
- first_tag -= 15;
- if (first_tag < 0)
- first_tag = 0;
- }
- else if ( key == 'd' || key == 'D' ) {
- first_tag += 15;
- if ( ( first_tag + 15 ) >= TAG_MAX )
- first_tag = TAG_MAX - 15;
- }
- else
- break;
- }
- }
-
-
- /*
- * This routine is called when a new pointer needs to be added to the tag
- * table. It can be a maverick pointer or a regular pointer.
- */
-
- void add_tag_to_table( char far *pointer,
- char maverick,
- size_t size,
- char *file_name,
- unsigned int line_number )
- {
- int i;
-
- if ( next_free_tag >= TAG_MAX )
- return;
- tag_table[ next_free_tag ].returned_address = pointer;
- tag_table[ next_free_tag ].real_address = pointer;
- tag_table[ next_free_tag ].size = size;
- tag_table[ next_free_tag ].file_name = file_name;
- tag_table[ next_free_tag ].line_number = line_number;
- tag_table[ next_free_tag ].maverick = maverick;
- if ( !maverick ) {
- for ( i = 0 ; i < PICKET_SIZE ; i++ )
- pointer[ i ] = leading_picket[ i ];
- pointer += size;
- pointer += PICKET_SIZE ;
- for ( i = 0 ; i < PICKET_SIZE ; i++ )
- pointer[ i ] = trailing_picket[ i ];
- tag_table[ next_free_tag ].returned_address += PICKET_SIZE;
- }
- next_free_tag++;
- }
-
-
- /*
- * This routine is called when a tag needs to be deleted from the table. This
- * can happen when a call to free() is made, or when a heapwalk shows that
- * one of the pointers is missing.
- */
-
- void delete_tag_from_table( int tag )
- {
- int i;
-
- next_free_tag--;
- for ( i = tag ; i < next_free_tag ; i++ )
- tag_table[ i ] = tag_table[ i + 1 ];
- tag_table[ i ].returned_address = NULL;
- tag_table[ i ].file_name = "Not in use";
- tag_table[ i ].line_number = 0;
- tag_table[ i ].size = 0;
- }
-
-
- /*
- * This is the verify routine that is called on the entry to my_malloc()
- * or my_free(). It calls the heap_walk() routine first, to let it do
- * its check out of the heap. It then goes through the entire tag table
- * and verifies that the pickets are all intact.
- */
-
- void verify_heap()
- {
- int i;
- int tag;
- char far *picket_pointer;
-
- initialize_tags();
- heap_walk();
- for ( tag = 0 ; tag < next_free_tag ; tag++ ) {
- if ( tag_table[ tag ].maverick )
- continue;
- picket_pointer = tag_table[ tag ].returned_address;
- picket_pointer -= PICKET_SIZE ;
- for ( i = 0 ; i < PICKET_SIZE ; i++ )
- if ( picket_pointer[ i ] != leading_picket[ i ] ) {
- screen_message( 0, i, "Error in leading picket, tag %3d", tag );
- break;
- }
- picket_pointer += PICKET_SIZE ;
- picket_pointer += tag_table[tag].size;
- for ( i = 0 ; i < PICKET_SIZE ; i++ )
- if ( picket_pointer[ i ] != trailing_picket[ i ] ) {
- screen_message( 0, tag, "Error in trailing picket, tag %3d", tag );
- break;
- }
- }
- }
-
- /*
- * This is the routine that walks through the heap. If an heap entry
- * is not found in the tag table, a message is printed, and it is added
- * as a maverick. Otherwise, the tag is noted. After walking through
- * the whole heap, a check is done to see if any of our tagged entries
- * didn't show up, which generates another message.
- *
- * Remember that this code is MSC-specific. You need to rewrite this
- * routine for every different compiler.
- */
-
- void heap_walk()
- {
- struct _heapinfo hinfo;
- int heapstatus;
- size_t size;
- int i;
-
- hinfo._pentry = NULL;
-
- for ( i = 0 ; i < next_free_tag ; i++ )
- tag_table[ i ].tagged = 0;
-
- for ( ; ; ) {
- heapstatus = _heapwalk( &hinfo );
- if ( heapstatus == _HEAPEMPTY )
- break;
- if ( heapstatus == _HEAPEND )
- break;
- if ( heapstatus != _HEAPOK ) {
- screen_message( 0, 0, "Heap is corrupted! Going to exit." );
- exit( 1 );
- }
- if ( hinfo._useflag != _USEDENTRY )
- continue;
- for ( i = 0 ; i < next_free_tag ; i++ ) {
- if ( (int far *) tag_table[ i ].real_address == hinfo._pentry ) {
- tag_table[ i ].tagged = 1;
- break;
- }
- }
- if ( i == next_free_tag ) {
- size = hinfo._size;
- if ( i < TAG_MAX )
- tag_table[ i ].tagged = 1;
- add_tag_to_table( (char far *) hinfo._pentry, 1, size, "MAVERICK",0 );
- screen_message( 0, i, "Found a maverick heap entry: %Fp", hinfo._pentry );
- }
- }
- /*
- * At this point every entry should have been tagged, so I can go through
- * the table and look for ones that didn't get tagged.
- */
- for ( i = 0 ; i < next_free_tag ; i++ ) {
- if ( tag_table[ i ].tagged == 0 ) {
- screen_message( 0, i, "Didn't find heap entry in heapwalk, tag %d", i );
- delete_tag_from_table( i );
- }
- }
- }
-
-
- /*
- * During the process of checking out the heap, if I see anything worthy
- * of a message, I call this routine. If the screen is not already up,
- * this guy pulls it up. Then it prints the message.
- */
-
- void screen_message( int immediate_return, int tag, char *format, ... )
- {
- char message[ 81 ];
- va_list args;
-
- if ( screen_up == 0 ) {
- screen_up = 1;
- message_line = 20;
- setup_screen( labels, widths, 15 );
- }
- va_start( args, format );
- vsprintf( message, format, args );
- screenputs( message_line, 0, message );
- if ( ++message_line >= 25 )
- message_line = 20;
- if ( !immediate_return )
- display_tag_table( tag );
- }
-
- /*
- * After all the work is done, I have to hide my heap screen so the user
- * can see the application output. This is pretty easy to do, a routine
- * in SCREEN.C does the whole job for me.
- */
- void hide_screen()
- {
- if ( screen_up != 0 ) {
- screen_up = 0;
- restore_screen();
- }
- }
-
-
-
-