From: bytheway%asylum.cs.utah.edu@cs.utah.edu (Sidney Bytheway)
Subject: Re: memory leak detection
Date: 29 Dec 92 11:27:53 MST
Organization: University of Utah CS Dept

In article <2423@sdrc.COM> crgreg@rios1.sdrc.com (Greg Marion) writes:
>I would like to know if anyone has heard of any software that would assist
>developers in detecting when an application allocates memory and does
>not free it. We would have to know which routine/function and maybe
>a range of line numbers that are suspect.
>
>Thanks


I wrote a malloc wrapper that increased the size of the malloc so I could
1) chain all of my malloced memory together, 2) tack on an informative string
3) attach a structure printing function, 4) check for storage violations.
The malloc wrapper returns a pointer to the "data" portion of the malloced
storage to the caller just like malloc.

At certain places I call a checking routing that will run through all of the
malloced memory and check for storage violations and, if requested, print the
invormative string and the memory using the printing function.

It has proved very useful.  I have included it below.

Sid Bytheway

---------------------------------------------------------------------------
  Sid Bytheway, (801) 581-3989    !  Internet: udpsid@snow.usi.utah.edu
  Senior Systems Programmer       !  Bitnet:   UDPSID at UTAHUSI
  Utah Supercomputing Institute   !  US Mail:  150 Park Bldg, SLC, UT 84112
---------------------------------------------------------------------------


/***********************************************************************
 *
 *	File:	sid_mem.h
 *	Desc:   Include file for the memory allocation and debugging
 *		routines.  Part of the Support for Improved Development
 *		(SID) library included in the TrISH Migration System.
 *
 *  Copyright:	Sid Bytheway
 *		University of Utah
 *		March 1992
 *
 * This code is supplied "AS IS" with no warranty expressed or implied.
 * Permission to copy, modify, distribute, fold, spindle and mutilate
 * this source code in any way shape or form is hereby granted to everyone.
 * Please include the proper credit.
 *
 ***********************************************************************/

#ifndef SID_MEM_H
#define SID_MEM_H


/*
 * Function Prototypes
 * -------------------
 */
char	*sid_malloc(long size, char *desc, int (*prtfunc)() );
int	 sid_free(char *ptr);
int	 sid_memscan(int print_flag);


/*
 * If we are not in DEBUG mode, over-ride all my memory allocation stuff
 * ---------------------------------------------------------------------
 */
#ifndef _DEBUG_

#define sid_malloc(size, desc, prtfunc) malloc(size)
#define sid_free(ptr) free(ptr)
#define sid_memscan(print_flag)   FALSE

#endif /* _DEBUG_ */


/*
 * Macro Definitions
 * -----------------
 *
 * Allocates memory for a new object of type objtype.
 *
 * Usage: ptr = newobj( structure_name );
 *	  delobj( ptr );
 */

#define	newobj(objtype)	\
	(objtype *) sid_malloc( sizeof(objtype), "objtype Object", NULL )

#define	delobj( obj ) \
	sid_free( (char *) obj )



#endif /* SID_MEM_H */


/***********************************************************************
 *
 *	File:   sid_mem.c
 *	Desc:   Contains memory allocation and debugging routines.
 *		Part of the Support for Improved Development (SID)
 *		library included in the TrISH Migration System.
 *
 *  Copyright:	Sid Bytheway
 *		University of Utah
 *		March 1992
 *
 * This code is supplied "AS IS" with no warranty expressed or implied.
 * Permission to copy, modify, distribute, fold, spindle and mutilate
 * this source code in any way shape or form is hereby granted to everyone.
 * Please include the proper credit.
 *
 * ----------------------------------------------------------------------
 *
 * Memory allocation debugging consists of allocating a little extra memory
 * for pattern checking fields, description string, pointers for printing
 * allocated memory, and the size of the user portion of the memory.
 *
 ***********************************************************************/

#ifndef _DEBUG_
# define _DEBUG_		/* required for this file */
#endif /* _DEBUG_ */

#include <stdio.h>
#include <signal.h>
#include <sys/types.h>

#include "sid.h"
#include "sid_mem.h"


/*
 * The memory check pattern - Define to anything you like.
 * -------------------------------------------------------
 */
#define	SID_CHECK_PATTERN 0xffabacab	/* storage violation pattern */


/*
 * This is the structure that glues all memory allocations together.
 * -----------------------------------------------------------------
 */
typedef struct _sid_memstruct {
    struct _sid_memstruct *next;	/* ptr to next memory allocation */
    struct _sid_memstruct *prev;	/* ptr to previous allocation */
    char    *desc;			/* char string description */
    long    usr_size;			/* size of user data */
    int	    (* prt_callback)();		/* callback func to print memory */
    long    check1;			/* first check field */
					/* user data is here */
    long    check2;			/* second check field */
} sid_memstruct;


/*
 * Global variables used by this file and these routines.
 * ------------------------------------------------------
 */
sid_memstruct *sid_mem_first;	/* first memory allocation */
sid_memstruct *sid_mem_last;	/* last memory allocation */



/*************************************************************
 *
 * sid_malloc()
 *
 *	My memory allocation routine that allocates memory and links
 *	it together with a description, printing function and fields
 *	to check for storage violations.
 *
 *************************************************************/
char *sid_malloc( 
	long	size,		/* size of user data */
	char	*desc,		/* char string description */
	int	(* prtfunc)()	/* callback func to print memory */
)
{

    char		*newch;
    sid_memstruct	*new;
    long		*check2;

    /* first scan memory to see if anything is hosed */
    sid_memscan( FALSE );

    /* allocate requested memory plus enough for tracing structure */
    if( (newch = (char *) malloc( size + sizeof(sid_memstruct))) == NULL ){
	fprintf(stderr, "sid_malloc(): Memory allocation error - %s\n", desc);
	exit( 1 );
    }
    new = (sid_memstruct *) newch;

    /* put data into my malloc structure */
    new->usr_size = size;
    new->desc = desc;
    new->prt_callback = prtfunc;
    new->check1 = SID_CHECK_PATTERN;
    check2 = (long *) (newch + size + sizeof(sid_memstruct) - sizeof(long));
    *check2 = SID_CHECK_PATTERN;

    /* link this dude in with everyone else */
    new->next = NULL;
    if( sid_mem_last != NULL )
	sid_mem_last->next = new;
    new->prev = sid_mem_last;
    sid_mem_last = new;
    if( sid_mem_first == NULL )
	sid_mem_first = new;

    /* return to the user a pointer to his data area */
    return( newch + sizeof(sid_memstruct) - sizeof(long) );

}


/*************************************************************
 *
 * sid_free()
 *
 *	My memory de-allocation routine.  Looks at storage violation
 *	fields for violations, prints a message if it finds one.
 *	Frees user and structure memory.
 *
 *************************************************************/
int sid_free(
	char *usr_data	    /* ptr to user data*/
)
{
    sid_memstruct	*ptr;
    long		*check2;

    /* Point to real head of allocated memory */
    ptr = (sid_memstruct *) (usr_data - sizeof(sid_memstruct) + sizeof(long));
    check2 = (long *) (usr_data + ptr->usr_size);

    /* unlink this dude from everyone else */
    if( ptr->prev == NULL )
	sid_mem_first = ptr->next;
    else
	ptr->prev->next = ptr->next;

    if( ptr->next == NULL )
	sid_mem_last = ptr->prev;
    else
	ptr->next->prev = ptr->prev;


    /* Check storage violation fields */
    if(ptr->check1 != SID_CHECK_PATTERN || *check2 != SID_CHECK_PATTERN) {
	fprintf(stderr, "sid_free: A storage violation has occured!!!\n" );
	fprintf(stderr, "desc = \"%s\"\n", ptr->desc );
	fprintf(stderr, "size = %d,  check1 = %8.8x,  check2 = %8.8x\n",
			ptr->usr_size, ptr->check1, *check2 );
	if( ptr->prt_callback != NULL ) {
	    fprintf( stderr, "sid_free: User Data Follows...\n\n" );
	    (* ptr->prt_callback)( usr_data );
	}
	fputc( '\n', stderr );
	fprintf( stderr, "Forcing core dump and exit\n" );
	kill( 0, SIGTRAP );
	exit( 1 );
    }

    return( free( (char *) ptr) );
}


/*************************************************************
 *
 * sid_memscan()
 *
 *	Scans all linked together storage looking for storage
 *	violations.  If print_flag is set then runs the callback
 *	routine to print the memory.  Returns 0 if no storage
 *	violations, 1 if any storage violations.
 *
 *************************************************************/
int sid_memscan(
	int print_flag
)
{
    sid_memstruct	*walker;
    char		*usr_data;
    long		*check2;
    int			violation, any_violation=FALSE;


    for(walker = sid_mem_first; walker != NULL; walker = walker->next) {

	violation = FALSE;
	usr_data = ((char *) walker) + sizeof(sid_memstruct) - sizeof(long);
	check2 = (long *) (usr_data + walker->usr_size);

	/* Test for storage violation - print messages if so */
	if( walker->check1 != SID_CHECK_PATTERN
	|| *check2 != SID_CHECK_PATTERN ) {
	    fprintf(stderr, "sid_memscan: A storage violation has occured!!!\n" );
	    fprintf(stderr, "desc = \"%s\"\n", walker->desc);
	    fprintf(stderr, "size = %d  check1 = %8.8x  check2 = %8.8x\n",
			    walker->usr_size, walker->check1, *check2 );
	    fprintf(stderr, "next = %8.8x, prev = %8.8x\n",
			    walker->next, walker->prev);
	    violation = TRUE;
	    any_violation = TRUE;
	}

	/* print the structure if violation or if print flag is set */
	if((violation || print_flag) && walker->prt_callback != NULL) {
	    fprintf( stderr, "sid_memscan: User Data Follows...\n\n" );
	    (* walker->prt_callback)( usr_data );
	}
	if( violation || (print_flag && walker->prt_callback != NULL))
	    fputc( '\n', stderr );
    }

    return( any_violation );

}

Newsgroups: comp.unix.aix