2005-10-16 18:33:22 +04:00
/*
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 - 2005 Red Hat , Inc . All rights reserved .
*
* This file is part of the device - mapper userspace tools .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include "lib.h"
# include <assert.h>
# include <stdarg.h>
2006-01-11 18:40:54 +03:00
char * dm_strdup_aux ( const char * str )
2005-10-16 18:33:22 +04:00
{
2005-10-17 02:57:20 +04:00
char * ret = dm_malloc ( strlen ( str ) + 1 ) ;
2005-10-16 18:33:22 +04:00
if ( ret )
strcpy ( ret , str ) ;
return ret ;
}
struct memblock {
struct memblock * prev , * next ; /* All allocated blocks are linked */
size_t length ; /* Size of the requested block */
int id ; /* Index of the block */
const char * file ; /* File that allocated */
int line ; /* Line that allocated */
void * magic ; /* Address of this block */
} ;
static struct {
unsigned block_serialno ; /* Non-decreasing serialno of block */
unsigned blocks_allocated ; /* Current number of blocks allocated */
unsigned blocks_max ; /* Max no of concurrently-allocated blocks */
unsigned int bytes , mbytes ;
} _mem_stats = {
0 , 0 , 0 , 0 , 0 } ;
static struct memblock * _head = 0 ;
static struct memblock * _tail = 0 ;
2005-11-10 19:33:04 +03:00
void * dm_malloc_aux_debug ( size_t s , const char * file , int line )
2005-10-16 18:33:22 +04:00
{
struct memblock * nb ;
size_t tsize = s + sizeof ( * nb ) + sizeof ( unsigned long ) ;
if ( s > 50000000 ) {
log_error ( " Huge memory allocation (size % " PRIsize_t
" ) rejected - metadata corruption? " , s ) ;
return 0 ;
}
if ( ! ( nb = malloc ( tsize ) ) ) {
log_error ( " couldn't allocate any memory, size = % " PRIsize_t ,
s ) ;
return 0 ;
}
/* set up the file and line info */
nb - > file = file ;
nb - > line = line ;
2005-10-17 02:57:20 +04:00
dm_bounds_check ( ) ;
2005-10-16 18:33:22 +04:00
/* setup fields */
nb - > magic = nb + 1 ;
nb - > length = s ;
nb - > id = + + _mem_stats . block_serialno ;
nb - > next = 0 ;
nb - > prev = _tail ;
/* link to tail of the list */
if ( ! _head )
_head = _tail = nb ;
else {
_tail - > next = nb ;
_tail = nb ;
}
/* stomp a pretty pattern across the new memory
and fill in the boundary bytes */
{
char * ptr = ( char * ) ( nb + 1 ) ;
size_t i ;
for ( i = 0 ; i < s ; i + + )
* ptr + + = i & 0x1 ? ( char ) 0xba : ( char ) 0xbe ;
for ( i = 0 ; i < sizeof ( unsigned long ) ; i + + )
* ptr + + = ( char ) nb - > id ;
}
_mem_stats . blocks_allocated + + ;
if ( _mem_stats . blocks_allocated > _mem_stats . blocks_max )
_mem_stats . blocks_max = _mem_stats . blocks_allocated ;
_mem_stats . bytes + = s ;
if ( _mem_stats . bytes > _mem_stats . mbytes )
_mem_stats . mbytes = _mem_stats . bytes ;
/* log_debug("Allocated: %u %u %u", nb->id, _mem_stats.blocks_allocated,
_mem_stats . bytes ) ; */
return nb + 1 ;
}
2005-10-17 02:57:20 +04:00
void dm_free_aux ( void * p )
2005-10-16 18:33:22 +04:00
{
char * ptr ;
size_t i ;
struct memblock * mb = ( ( struct memblock * ) p ) - 1 ;
if ( ! p )
return ;
2005-10-17 02:57:20 +04:00
dm_bounds_check ( ) ;
2005-10-16 18:33:22 +04:00
/* sanity check */
assert ( mb - > magic = = p ) ;
/* check data at the far boundary */
ptr = ( ( char * ) mb ) + sizeof ( struct memblock ) + mb - > length ;
for ( i = 0 ; i < sizeof ( unsigned long ) ; i + + )
if ( * ptr + + ! = ( char ) mb - > id )
assert ( ! " Damage at far end of block " ) ;
/* have we freed this before ? */
assert ( mb - > id ! = 0 ) ;
mb - > id = 0 ;
/* stomp a different pattern across the memory */
ptr = ( ( char * ) mb ) + sizeof ( struct memblock ) ;
for ( i = 0 ; i < mb - > length ; i + + )
* ptr + + = i & 1 ? ( char ) 0xde : ( char ) 0xad ;
/* unlink */
if ( mb - > prev )
mb - > prev - > next = mb - > next ;
else
_head = mb - > next ;
if ( mb - > next )
mb - > next - > prev = mb - > prev ;
else
_tail = mb - > prev ;
assert ( _mem_stats . blocks_allocated ) ;
_mem_stats . blocks_allocated - - ;
_mem_stats . bytes - = mb - > length ;
/* free the memory */
free ( mb ) ;
}
2005-10-17 02:57:20 +04:00
void * dm_realloc_aux ( void * p , unsigned int s , const char * file , int line )
2005-10-16 18:33:22 +04:00
{
void * r ;
struct memblock * mb = ( ( struct memblock * ) p ) - 1 ;
2005-11-10 19:33:04 +03:00
r = dm_malloc_aux_debug ( s , file , line ) ;
2005-10-16 18:33:22 +04:00
if ( p ) {
memcpy ( r , p , mb - > length ) ;
2005-10-17 02:57:20 +04:00
dm_free_aux ( p ) ;
2005-10-16 18:33:22 +04:00
}
return r ;
}
2005-11-10 19:33:04 +03:00
int dm_dump_memory_debug ( void )
2005-10-16 18:33:22 +04:00
{
unsigned long tot = 0 ;
struct memblock * mb ;
char str [ 32 ] ;
size_t c ;
if ( _head )
log_very_verbose ( " You have a memory leak: " ) ;
for ( mb = _head ; mb ; mb = mb - > next ) {
for ( c = 0 ; c < sizeof ( str ) - 1 ; c + + ) {
if ( c > = mb - > length )
str [ c ] = ' ' ;
else if ( * ( char * ) ( mb - > magic + c ) = = ' \0 ' )
str [ c ] = ' \0 ' ;
else if ( * ( char * ) ( mb - > magic + c ) < ' ' )
str [ c ] = ' ? ' ;
else
str [ c ] = * ( char * ) ( mb - > magic + c ) ;
}
str [ sizeof ( str ) - 1 ] = ' \0 ' ;
2006-01-31 17:50:38 +03:00
dm_log ( _LOG_INFO , mb - > file , mb - > line ,
" block %d at %p, size % " PRIsize_t " \t [%s] " ,
mb - > id , mb - > magic , mb - > length , str ) ;
2005-10-16 18:33:22 +04:00
tot + = mb - > length ;
}
if ( _head )
log_very_verbose ( " %ld bytes leaked in total " , tot ) ;
return 1 ;
}
2005-11-10 19:33:04 +03:00
void dm_bounds_check_debug ( void )
2005-10-16 18:33:22 +04:00
{
struct memblock * mb = _head ;
while ( mb ) {
size_t i ;
char * ptr = ( ( char * ) ( mb + 1 ) ) + mb - > length ;
for ( i = 0 ; i < sizeof ( unsigned long ) ; i + + )
if ( * ptr + + ! = ( char ) mb - > id )
assert ( ! " Memory smash " ) ;
mb = mb - > next ;
}
}
2005-10-17 02:57:20 +04:00
void * dm_malloc_aux ( size_t s , const char * file , int line )
2005-10-16 18:33:22 +04:00
{
if ( s > 50000000 ) {
log_error ( " Huge memory allocation (size % " PRIsize_t
" ) rejected - metadata corruption? " , s ) ;
return 0 ;
}
return malloc ( s ) ;
}