Blame src/papi_memory.c

Packit 577717
/**
Packit 577717
 * @file    papi_memory.c
Packit 577717
 * @author  Kevin London
Packit 577717
 *          london@cs.utk.edu
Packit 577717
 * PAPI memory allocation provides for checking and maintenance of all memory
Packit 577717
 * allocated through this interface. Implemented as a series of wrappers around
Packit 577717
 * standard C memory allocation routines, _papi_malloc and associated functions
Packit 577717
 * add a prolog and optional epilog to each malloc'd pointer.
Packit 577717
 * The prolog, sized to preserve memory alignment, contains a pointer to a 
Packit 577717
 * linked list of pmem_t structures that describe every block of memory 
Packit 577717
 * allocated through these calls.
Packit 577717
 * The optional epilog is enabled if DEBUG is defined, and contains 
Packit 577717
 * a distinctive pattern that allows checking for pointer overflow.
Packit 577717
 */
Packit 577717
Packit 577717
#define IN_MEM_FILE
Packit 577717
Packit 577717
#include <stdio.h>
Packit 577717
#include <stdlib.h>
Packit 577717
#include <string.h>
Packit 577717
#include "papi.h"
Packit 577717
#include "papi_lock.h"
Packit 577717
#include "papi_memory.h"
Packit 577717
#include "papi_internal.h"
Packit 577717
Packit 577717
Packit 577717
/** Define the amount of extra memory at the beginning of the alloc'd pointer.
Packit 577717
 * This is usually the size of a pointer, but in some cases needs to be bigger
Packit 577717
 * to preserve data alignment.
Packit 577717
 */
Packit 577717
#define MEM_PROLOG (2*sizeof(void *))
Packit 577717
Packit 577717
/* If you are tracing memory, then DEBUG must be set also. */
Packit 577717
#ifdef DEBUG
Packit 577717
/** Define the amount of extra memory at the end of the alloc'd pointer.
Packit 577717
 * Also define the contents: 0xCACA
Packit 577717
 */
Packit 577717
#define MEM_EPILOG 4
Packit 577717
#define MEM_EPILOG_1 0xC
Packit 577717
#define MEM_EPILOG_2 0xA
Packit 577717
#define MEM_EPILOG_3 0xC
Packit 577717
#define MEM_EPILOG_4 0xA
Packit 577717
#endif
Packit 577717
Packit 577717
/* Local global variables */
Packit 577717
static pmem_t *mem_head = NULL;
Packit 577717
Packit 577717
/* Local Prototypes */
Packit 577717
static pmem_t *get_mem_ptr( void *ptr );
Packit 577717
static pmem_t *init_mem_ptr( void *, int, char *, int );
Packit 577717
static void insert_mem_ptr( pmem_t * );
Packit 577717
static void remove_mem_ptr( pmem_t * );
Packit 577717
static int set_epilog( pmem_t * mem_ptr );
Packit 577717
Packit 577717
/**********************************************************************
Packit 577717
 * Exposed papi versions of std memory management routines:           *
Packit 577717
 *  _papi_realloc                                                     *
Packit 577717
 *  _papi_calloc                                                      *
Packit 577717
 *  _papi_malloc                                                      *
Packit 577717
 *  _papi_strdup                                                      *
Packit 577717
 *  _papi_free                                                        *
Packit 577717
 *  _papi_valid_free                                                  *
Packit 577717
 * Exposed useful papi memory maintenance routines:                   *
Packit 577717
 *  _papi_mem_print_info                                              *
Packit 577717
 *  _papi_mem_print_stats                                             *
Packit 577717
 *  _papi_mem_overhead                                                *
Packit 577717
 *  _papi_mem_cleanup_all                                             *
Packit 577717
 *  _papi_mem_check_buf_overflow                                      *
Packit 577717
 *  _papi_mem_check_all_overflow                                      *
Packit 577717
 **********************************************************************/
Packit 577717
Packit 577717
/** _papi_realloc -- given a pointer returned by _papi_malloc, returns a pointer
Packit 577717
 * to the related pmem_t structure describing this pointer.
Packit 577717
 * Checks for NULL pointers and returns NULL if error.
Packit 577717
 */
Packit 577717
void *
Packit 577717
_papi_realloc( char *file, int line, void *ptr, size_t size )
Packit 577717
{
Packit 577717
	size_t nsize = size + MEM_PROLOG;
Packit 577717
	pmem_t *mem_ptr;
Packit 577717
	void *nptr;
Packit 577717
Packit 577717
#ifdef DEBUG
Packit 577717
	nsize += MEM_EPILOG;
Packit 577717
	_papi_hwi_lock( MEMORY_LOCK );
Packit 577717
	_papi_mem_check_all_overflow(  );
Packit 577717
#endif
Packit 577717
Packit 577717
	if ( !ptr )
Packit 577717
		return ( _papi_malloc( file, line, size ) );
Packit 577717
Packit 577717
	mem_ptr = get_mem_ptr( ptr );
Packit 577717
	nptr = ( pmem_t * ) realloc( ( ( char * ) ptr - MEM_PROLOG ), nsize );
Packit 577717
Packit 577717
	if ( !nptr )
Packit 577717
		return ( NULL );
Packit 577717
Packit 577717
	mem_ptr->size = ( int ) size;
Packit 577717
	mem_ptr->ptr = ( char * ) nptr + MEM_PROLOG;
Packit 577717
#ifdef DEBUG
Packit 577717
	strncpy( mem_ptr->file, file, DEBUG_FILE_LEN );
Packit 577717
	mem_ptr->file[DEBUG_FILE_LEN - 1] = '\0';
Packit 577717
	mem_ptr->line = line;
Packit 577717
	set_epilog( mem_ptr );
Packit 577717
	_papi_hwi_unlock( MEMORY_LOCK );
Packit 577717
#endif
Packit 577717
	MEMDBG( "%p: Re-allocated: %lu bytes from File: %s  Line: %d\n",
Packit 577717
			mem_ptr->ptr, ( unsigned long ) size, file, line );
Packit 577717
	return ( mem_ptr->ptr );
Packit 577717
}
Packit 577717
Packit 577717
void *
Packit 577717
_papi_calloc( char *file, int line, size_t nmemb, size_t size )
Packit 577717
{
Packit 577717
	void *ptr = _papi_malloc( file, line, size * nmemb );
Packit 577717
Packit 577717
	if ( !ptr )
Packit 577717
		return ( NULL );
Packit 577717
	memset( ptr, 0, size * nmemb );
Packit 577717
	return ( ptr );
Packit 577717
}
Packit 577717
Packit 577717
void *
Packit 577717
_papi_malloc( char *file, int line, size_t size )
Packit 577717
{
Packit 577717
	void *ptr;
Packit 577717
	void **tmp;
Packit 577717
	pmem_t *mem_ptr;
Packit 577717
	size_t nsize = size + MEM_PROLOG;
Packit 577717
Packit 577717
#ifdef DEBUG
Packit 577717
	nsize += MEM_EPILOG;
Packit 577717
#endif
Packit 577717
Packit 577717
	if ( size == 0 ) {
Packit 577717
		MEMDBG( "Attempting to allocate %lu bytes from File: %s  Line: %d\n",
Packit 577717
				( unsigned long ) size, file, line );
Packit 577717
		return ( NULL );
Packit 577717
	}
Packit 577717
Packit 577717
	ptr = ( void * ) malloc( nsize );
Packit 577717
Packit 577717
	if ( !ptr )
Packit 577717
		return ( NULL );
Packit 577717
	else {
Packit 577717
		if ( ( mem_ptr =
Packit 577717
			   init_mem_ptr( ( char * ) ptr + MEM_PROLOG, ( int ) size, file,
Packit 577717
							 line ) ) == NULL ) {
Packit 577717
			free( ptr );
Packit 577717
			return ( NULL );
Packit 577717
		}
Packit 577717
		tmp = ptr;
Packit 577717
		*tmp = mem_ptr;
Packit 577717
		ptr = mem_ptr->ptr;
Packit 577717
		mem_ptr->ptr = ptr;
Packit 577717
		_papi_hwi_lock( MEMORY_LOCK );
Packit 577717
		insert_mem_ptr( mem_ptr );
Packit 577717
		set_epilog( mem_ptr );
Packit 577717
		_papi_hwi_unlock( MEMORY_LOCK );
Packit 577717
Packit 577717
		MEMDBG( "%p: Allocated %lu bytes from File: %s  Line: %d\n",
Packit 577717
				mem_ptr->ptr, ( unsigned long ) size, file, line );
Packit 577717
		return ( ptr );
Packit 577717
	}
Packit 577717
	return ( NULL );
Packit 577717
}
Packit 577717
Packit 577717
char *
Packit 577717
_papi_strdup( char *file, int line, const char *s )
Packit 577717
{
Packit 577717
	size_t size;
Packit 577717
	char *ptr;
Packit 577717
Packit 577717
	if ( !s )
Packit 577717
		return ( NULL );
Packit 577717
Packit 577717
	/* String Length +1 for \0 */
Packit 577717
	size = strlen( s ) + 1;
Packit 577717
	ptr = ( char * ) _papi_malloc( file, line, size );
Packit 577717
Packit 577717
	if ( !ptr )
Packit 577717
		return ( NULL );
Packit 577717
Packit 577717
	memcpy( ptr, s, size );
Packit 577717
	return ( ptr );
Packit 577717
}
Packit 577717
Packit 577717
/** Only frees the memory if PAPI malloced it 
Packit 577717
  * returns 1 if pointer was valid; 0 if not */
Packit 577717
int
Packit 577717
_papi_valid_free( char *file, int line, void *ptr )
Packit 577717
{
Packit 577717
	pmem_t *tmp;
Packit 577717
	int valid = 0;
Packit 577717
Packit 577717
	if ( !ptr ) {
Packit 577717
		( void ) file;
Packit 577717
		( void ) line;
Packit 577717
		return ( 0 );
Packit 577717
	}
Packit 577717
Packit 577717
	_papi_hwi_lock( MEMORY_LOCK );
Packit 577717
Packit 577717
	for ( tmp = mem_head; tmp; tmp = tmp->next ) {
Packit 577717
		if ( ptr == tmp->ptr ) {
Packit 577717
			pmem_t *mem_ptr = get_mem_ptr( ptr );
Packit 577717
Packit 577717
			if ( mem_ptr ) {
Packit 577717
				MEMDBG( "%p: Freeing %d bytes from File: %s  Line: %d\n",
Packit 577717
						mem_ptr->ptr, mem_ptr->size, file, line );
Packit 577717
				remove_mem_ptr( mem_ptr );
Packit 577717
				_papi_mem_check_all_overflow(  );
Packit 577717
			}
Packit 577717
Packit 577717
			valid = 1;
Packit 577717
			break;
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	_papi_hwi_unlock( MEMORY_LOCK );
Packit 577717
	return ( valid );
Packit 577717
}
Packit 577717
Packit 577717
/** Frees up the ptr */
Packit 577717
void
Packit 577717
_papi_free( char *file, int line, void *ptr )
Packit 577717
{
Packit 577717
	pmem_t *mem_ptr = get_mem_ptr( ptr );
Packit 577717
Packit 577717
	if ( !mem_ptr ) {
Packit 577717
		( void ) file;
Packit 577717
		( void ) line;
Packit 577717
		return;
Packit 577717
	}
Packit 577717
Packit 577717
	MEMDBG( "%p: Freeing %d bytes from File: %s  Line: %d\n", mem_ptr->ptr,
Packit 577717
			mem_ptr->size, file, line );
Packit 577717
Packit 577717
	_papi_hwi_lock( MEMORY_LOCK );
Packit 577717
	remove_mem_ptr( mem_ptr );
Packit 577717
	_papi_mem_check_all_overflow(  );
Packit 577717
	_papi_hwi_unlock( MEMORY_LOCK );
Packit 577717
}
Packit 577717
Packit 577717
/** Print information about the memory including file and location it came from */
Packit 577717
void
Packit 577717
_papi_mem_print_info( void *ptr )
Packit 577717
{
Packit 577717
	pmem_t *mem_ptr = get_mem_ptr( ptr );
Packit 577717
Packit 577717
#ifdef DEBUG
Packit 577717
	fprintf( stderr, "%p: Allocated %d bytes from File: %s  Line: %d\n", ptr,
Packit 577717
			 mem_ptr->size, mem_ptr->file, mem_ptr->line );
Packit 577717
#else
Packit 577717
	fprintf( stderr, "%p: Allocated %d bytes\n", ptr, mem_ptr->size );
Packit 577717
#endif
Packit 577717
	return;
Packit 577717
}
Packit 577717
Packit 577717
/** Print out all memory information */
Packit 577717
void
Packit 577717
_papi_mem_print_stats(  )
Packit 577717
{
Packit 577717
	pmem_t *tmp = NULL;
Packit 577717
Packit 577717
	_papi_hwi_lock( MEMORY_LOCK );
Packit 577717
	for ( tmp = mem_head; tmp; tmp = tmp->next ) {
Packit 577717
		_papi_mem_print_info( tmp->ptr );
Packit 577717
	}
Packit 577717
	_papi_hwi_unlock( MEMORY_LOCK );
Packit 577717
}
Packit 577717
Packit 577717
/** Return the amount of memory overhead of the PAPI library and the memory system
Packit 577717
 * PAPI_MEM_LIB_OVERHEAD is the library overhead
Packit 577717
 * PAPI_MEM_OVERHEAD is the memory overhead
Packit 577717
 * They both can be | together
Packit 577717
 * This only includes "malloc'd memory"
Packit 577717
 */
Packit 577717
int
Packit 577717
_papi_mem_overhead( int type )
Packit 577717
{
Packit 577717
	pmem_t *ptr = NULL;
Packit 577717
	int size = 0;
Packit 577717
Packit 577717
	_papi_hwi_lock( MEMORY_LOCK );
Packit 577717
	for ( ptr = mem_head; ptr; ptr = ptr->next ) {
Packit 577717
		if ( type & PAPI_MEM_LIB_OVERHEAD )
Packit 577717
			size += ptr->size;
Packit 577717
		if ( type & PAPI_MEM_OVERHEAD ) {
Packit 577717
			size += ( int ) sizeof ( pmem_t );
Packit 577717
			size += ( int ) MEM_PROLOG;
Packit 577717
#ifdef DEBUG
Packit 577717
			size += ( int ) MEM_EPILOG;
Packit 577717
#endif
Packit 577717
		}
Packit 577717
	}
Packit 577717
	_papi_hwi_unlock( MEMORY_LOCK );
Packit 577717
	return size;
Packit 577717
}
Packit 577717
Packit 577717
/** Clean all memory up and print out memory leak information to stderr */
Packit 577717
void
Packit 577717
_papi_mem_cleanup_all(  )
Packit 577717
{
Packit 577717
	pmem_t *ptr = NULL, *tmp = NULL;
Packit 577717
#ifdef DEBUG
Packit 577717
	int cnt = 0;
Packit 577717
#endif
Packit 577717
Packit 577717
	_papi_hwi_lock( MEMORY_LOCK );
Packit 577717
	_papi_mem_check_all_overflow(  );
Packit 577717
Packit 577717
	for ( ptr = mem_head; ptr; ptr = tmp ) {
Packit 577717
		tmp = ptr->next;
Packit 577717
#ifdef DEBUG
Packit 577717
		LEAKDBG( "MEMORY LEAK: %p of %d bytes, from File: %s Line: %d\n",
Packit 577717
				 ptr->ptr, ptr->size, ptr->file, ptr->line );
Packit 577717
		cnt += ptr->size;
Packit 577717
#endif
Packit 577717
Packit 577717
		remove_mem_ptr( ptr );
Packit 577717
	}
Packit 577717
	_papi_hwi_unlock( MEMORY_LOCK );
Packit 577717
#ifdef DEBUG
Packit 577717
	if ( 0 != cnt ) { 
Packit 577717
		LEAKDBG( "TOTAL MEMORY LEAK: %d bytes.\n", cnt );
Packit 577717
	}
Packit 577717
#endif
Packit 577717
}
Packit 577717
Packit 577717
/* Loop through memory structures and look for buffer overflows 
Packit 577717
 * returns the number of overflows detected
Packit 577717
 */
Packit 577717
Packit 577717
/**********************************************************************
Packit 577717
 * Private helper routines for papi memory management                 *
Packit 577717
 **********************************************************************/
Packit 577717
Packit 577717
/* Given a pointer returned by _papi_malloc, returns a pointer
Packit 577717
 * to the related pmem_t structure describing this pointer.
Packit 577717
 * Checks for NULL pointers and returns NULL if error.
Packit 577717
 */
Packit 577717
static pmem_t *
Packit 577717
get_mem_ptr( void *ptr )
Packit 577717
{
Packit 577717
	pmem_t **tmp_ptr = ( pmem_t ** ) ( ( char * ) ptr - MEM_PROLOG );
Packit 577717
	pmem_t *mem_ptr;
Packit 577717
Packit 577717
	if ( !tmp_ptr || !ptr )
Packit 577717
		return ( NULL );
Packit 577717
Packit 577717
	mem_ptr = *tmp_ptr;
Packit 577717
	return ( mem_ptr );
Packit 577717
}
Packit 577717
Packit 577717
/* Allocate and initialize a memory pointer */
Packit 577717
pmem_t *
Packit 577717
init_mem_ptr( void *ptr, int size, char *file, int line )
Packit 577717
{
Packit 577717
	pmem_t *mem_ptr = NULL;
Packit 577717
	if ( ( mem_ptr = ( pmem_t * ) malloc( sizeof ( pmem_t ) ) ) == NULL )
Packit 577717
		return ( NULL );
Packit 577717
Packit 577717
	mem_ptr->ptr = ptr;
Packit 577717
	mem_ptr->size = size;
Packit 577717
	mem_ptr->next = NULL;
Packit 577717
	mem_ptr->prev = NULL;
Packit 577717
#ifdef DEBUG
Packit 577717
	strncpy( mem_ptr->file, file, DEBUG_FILE_LEN );
Packit 577717
	mem_ptr->file[DEBUG_FILE_LEN - 1] = '\0';
Packit 577717
	mem_ptr->line = line;
Packit 577717
#else
Packit 577717
	( void ) file;			 /*unused */
Packit 577717
	( void ) line;			 /*unused */
Packit 577717
#endif
Packit 577717
	return ( mem_ptr );
Packit 577717
}
Packit 577717
Packit 577717
/* Insert the memory information 
Packit 577717
 * Do not lock these routines, but lock in routines using these
Packit 577717
 */
Packit 577717
static void
Packit 577717
insert_mem_ptr( pmem_t * ptr )
Packit 577717
{
Packit 577717
	if ( !ptr )
Packit 577717
		return;
Packit 577717
Packit 577717
	if ( !mem_head ) {
Packit 577717
		mem_head = ptr;
Packit 577717
		ptr->next = NULL;
Packit 577717
		ptr->prev = NULL;
Packit 577717
	} else {
Packit 577717
		mem_head->prev = ptr;
Packit 577717
		ptr->next = mem_head;
Packit 577717
		mem_head = ptr;
Packit 577717
	}
Packit 577717
	return;
Packit 577717
}
Packit 577717
Packit 577717
/* Remove the memory information pointer and free the memory 
Packit 577717
 * Do not using locking in this routine, instead lock around 
Packit 577717
 * the sections of code that use this call.
Packit 577717
 */
Packit 577717
static void
Packit 577717
remove_mem_ptr( pmem_t * ptr )
Packit 577717
{
Packit 577717
	if ( !ptr )
Packit 577717
		return;
Packit 577717
Packit 577717
	if ( ptr->prev )
Packit 577717
		ptr->prev->next = ptr->next;
Packit 577717
	if ( ptr->next )
Packit 577717
		ptr->next->prev = ptr->prev;
Packit 577717
	if ( ptr == mem_head )
Packit 577717
		mem_head = ptr->next;
Packit 577717
	free( ptr );
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
set_epilog( pmem_t * mem_ptr )
Packit 577717
{
Packit 577717
#ifdef DEBUG
Packit 577717
	char *chptr = ( char * ) mem_ptr->ptr + mem_ptr->size;
Packit 577717
	*chptr++ = MEM_EPILOG_1;
Packit 577717
	*chptr++ = MEM_EPILOG_2;
Packit 577717
	*chptr++ = MEM_EPILOG_3;
Packit 577717
	*chptr++ = MEM_EPILOG_4;
Packit 577717
	return ( _papi_mem_check_all_overflow(  ) );
Packit 577717
#else
Packit 577717
	( void ) mem_ptr;		 /*unused */
Packit 577717
#endif
Packit 577717
	return ( 0 );
Packit 577717
}
Packit 577717
Packit 577717
/* Check for memory buffer overflows */
Packit 577717
#ifdef DEBUG
Packit 577717
static int
Packit 577717
_papi_mem_check_buf_overflow( pmem_t * tmp )
Packit 577717
{
Packit 577717
	int fnd = 0;
Packit 577717
	char *ptr;
Packit 577717
	char *tptr;
Packit 577717
Packit 577717
	if ( !tmp )
Packit 577717
		return ( 0 );
Packit 577717
Packit 577717
	tptr = tmp->ptr;
Packit 577717
	tptr += tmp->size;
Packit 577717
Packit 577717
	/* Move to the buffer overflow padding */
Packit 577717
	ptr = ( ( char * ) tmp->ptr ) + tmp->size;
Packit 577717
	if ( *ptr++ != MEM_EPILOG_1 )
Packit 577717
		fnd = 1;
Packit 577717
	else if ( *ptr++ != MEM_EPILOG_2 )
Packit 577717
		fnd = 2;
Packit 577717
	else if ( *ptr++ != MEM_EPILOG_3 )
Packit 577717
		fnd = 3;
Packit 577717
	else if ( *ptr++ != MEM_EPILOG_4 )
Packit 577717
		fnd = 4;
Packit 577717
Packit 577717
	if ( fnd ) {
Packit 577717
		LEAKDBG( "Buffer Overflow[%d] for %p allocated from %s at line %d\n",
Packit 577717
				 fnd, tmp->ptr, tmp->file, tmp->line );
Packit 577717
	}
Packit 577717
	return ( fnd );
Packit 577717
}
Packit 577717
#endif
Packit 577717
Packit 577717
int
Packit 577717
_papi_mem_check_all_overflow(  )
Packit 577717
{
Packit 577717
	int fnd = 0;
Packit 577717
#ifdef DEBUG
Packit 577717
	pmem_t *tmp;
Packit 577717
Packit 577717
	for ( tmp = mem_head; tmp; tmp = tmp->next ) {
Packit 577717
		if ( _papi_mem_check_buf_overflow( tmp ) )
Packit 577717
			fnd++;
Packit 577717
	}
Packit 577717
Packit 577717
	if ( fnd ) {
Packit 577717
		LEAKDBG( "%d Total Buffer overflows detected!\n", fnd );
Packit 577717
	}
Packit 577717
#endif
Packit 577717
	return ( fnd );
Packit 577717
}