2005-10-16 18:33:22 +04:00
/*
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2011-10-29 00:37:31 +04:00
* Copyright ( C ) 2004 - 2011 Red Hat , Inc . All rights reserved .
2005-10-16 18:33:22 +04:00
*
* 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
2007-08-21 20:26:07 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2005-10-16 18:33:22 +04:00
*
2007-08-21 20:26:07 +04:00
* You should have received a copy of the GNU Lesser General Public License
2005-10-16 18:33:22 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-10-16 18:33:22 +04:00
*/
2008-11-03 21:59:59 +03:00
# include "dmlib.h"
2005-10-16 18:33:22 +04:00
2011-10-29 00:37:31 +04:00
# ifdef VALGRIND_POOL
2012-10-09 22:54:41 +04:00
# include "memcheck.h"
2011-10-29 00:37:31 +04:00
# endif
2005-10-16 18:33:22 +04:00
# include <assert.h>
# include <stdarg.h>
2015-07-23 01:03:32 +03:00
void * dm_malloc_aux ( size_t s , const char * file , int line )
__attribute__ ( ( __malloc__ ) ) __attribute__ ( ( __warn_unused_result__ ) ) ;
void * dm_malloc_aux_debug ( size_t s , const char * file , int line )
__attribute__ ( ( __malloc__ ) ) __attribute__ ( ( __warn_unused_result__ ) ) ;
void * dm_zalloc_aux ( size_t s , const char * file , int line )
__attribute__ ( ( __malloc__ ) ) __attribute__ ( ( __warn_unused_result__ ) ) ;
void * dm_zalloc_aux_debug ( size_t s , const char * file , int line )
__attribute__ ( ( __malloc__ ) ) __attribute__ ( ( __warn_unused_result__ ) ) ;
void * dm_realloc_aux ( void * p , unsigned int s , const char * file , int line )
__attribute__ ( ( __warn_unused_result__ ) ) ;
void dm_free_aux ( void * p ) ;
char * dm_strdup_aux ( const char * str , const char * file , int line )
__attribute__ ( ( __warn_unused_result__ ) ) ;
int dm_dump_memory_debug ( void ) ;
void dm_bounds_check_debug ( void ) ;
2006-02-23 22:11:51 +03:00
char * dm_strdup_aux ( const char * str , const char * file , int line )
2005-10-16 18:33:22 +04:00
{
2007-01-15 17:39:12 +03:00
char * ret ;
2005-10-16 18:33:22 +04:00
2007-01-15 17:39:12 +03:00
if ( ! str ) {
2010-03-25 21:22:04 +03:00
log_error ( INTERNAL_ERROR " dm_strdup called with NULL pointer " ) ;
2007-01-15 17:39:12 +03:00
return NULL ;
}
if ( ( ret = dm_malloc_aux_debug ( strlen ( str ) + 1 , file , line ) ) )
2005-10-16 18:33:22 +04:00
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 */
2008-06-25 18:10:33 +04:00
} __attribute__ ( ( aligned ( 8 ) ) ) ;
2005-10-16 18:33:22 +04:00
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 ;
/* 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 ;
}
2006-08-19 01:38:58 +04:00
nb - > prev = _tail ;
/* link to tail of the list */
if ( ! _head )
_head = _tail = nb ;
else {
_tail - > next = nb ;
_tail = nb ;
}
2005-10-16 18:33:22 +04:00
_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 ;
2013-01-08 02:30:29 +04:00
/* log_debug_mem("Allocated: %u %u %u", nb->id, _mem_stats.blocks_allocated,
2005-10-16 18:33:22 +04:00
_mem_stats . bytes ) ; */
2011-10-29 00:37:31 +04:00
# ifdef VALGRIND_POOL
VALGRIND_MAKE_MEM_UNDEFINED ( nb + 1 , s ) ;
# endif
2005-10-16 18:33:22 +04:00
return nb + 1 ;
}
2010-10-01 01:06:50 +04:00
void * dm_zalloc_aux_debug ( size_t s , const char * file , int line )
{
void * ptr = dm_malloc_aux_debug ( s , file , line ) ;
if ( ptr )
memset ( ptr , 0 , s ) ;
return ptr ;
}
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 ) ;
2011-10-29 00:37:31 +04:00
# ifdef VALGRIND_POOL
VALGRIND_MAKE_MEM_DEFINED ( p , mb - > length ) ;
# endif
2005-10-16 18:33:22 +04:00
/* check data at the far boundary */
2011-10-20 17:33:41 +04:00
ptr = ( char * ) p + mb - > length ;
2005-10-16 18:33:22 +04:00
for ( i = 0 ; i < sizeof ( unsigned long ) ; i + + )
2011-10-20 17:33:41 +04:00
if ( ptr [ i ] ! = ( char ) mb - > id )
2005-10-16 18:33:22 +04:00
assert ( ! " Damage at far end of block " ) ;
/* have we freed this before ? */
assert ( mb - > id ! = 0 ) ;
/* 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 ;
2006-09-19 21:30:04 +04:00
mb - > id = 0 ;
/* stomp a different pattern across the memory */
2011-10-20 17:33:41 +04:00
ptr = p ;
2006-09-19 21:30:04 +04:00
for ( i = 0 ; i < mb - > length ; i + + )
2011-10-20 17:33:41 +04:00
ptr [ i ] = i & 1 ? ( char ) 0xde : ( char ) 0xad ;
2006-09-19 21:30:04 +04:00
2005-10-16 18:33:22 +04:00
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
2012-02-10 17:52:05 +04:00
if ( r & & p ) {
2005-10-16 18:33:22 +04:00
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 ] ;
if ( _head )
log_very_verbose ( " You have a memory leak: " ) ;
for ( mb = _head ; mb ; mb = mb - > next ) {
2010-08-09 14:56:01 +04:00
# ifdef VALGRIND_POOL
/*
* We can ' t look at the memory in case it has had
* VALGRIND_MAKE_MEM_NOACCESS called on it .
*/
str [ 0 ] = ' \0 ' ;
# else
2014-03-27 14:21:05 +04:00
size_t c ;
2005-10-16 18:33:22 +04:00
for ( c = 0 ; c < sizeof ( str ) - 1 ; c + + ) {
if ( c > = mb - > length )
str [ c ] = ' ' ;
2010-08-03 17:24:07 +04:00
else if ( ( ( char * ) mb - > magic ) [ c ] = = ' \0 ' )
2005-10-16 18:33:22 +04:00
str [ c ] = ' \0 ' ;
2010-08-03 17:24:07 +04:00
else if ( ( ( char * ) mb - > magic ) [ c ] < ' ' )
2005-10-16 18:33:22 +04:00
str [ c ] = ' ? ' ;
else
2010-08-03 17:24:07 +04:00
str [ c ] = ( ( char * ) mb - > magic ) [ c ] ;
2005-10-16 18:33:22 +04:00
}
str [ sizeof ( str ) - 1 ] = ' \0 ' ;
2010-08-09 14:56:01 +04:00
# endif
2005-10-16 18:33:22 +04:00
2009-07-16 04:52:06 +04:00
LOG_MESG ( _LOG_INFO , mb - > file , mb - > line , 0 ,
2009-07-10 13:59:37 +04:00
" 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 ;
}
}
2010-07-09 19:34:40 +04:00
void * dm_malloc_aux ( size_t s , const char * file __attribute__ ( ( unused ) ) ,
int line __attribute__ ( ( unused ) ) )
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 ) ;
}
2010-10-01 01:06:50 +04:00
void * dm_zalloc_aux ( size_t s , const char * file , int line )
{
void * ptr = dm_malloc_aux ( s , file , line ) ;
if ( ptr )
memset ( ptr , 0 , s ) ;
return ptr ;
}
2015-07-23 01:03:32 +03:00
# ifdef DEBUG_MEM
void * dm_malloc_wrapper ( size_t s , const char * file , int line )
{
return dm_malloc_aux_debug ( s , file , line ) ;
}
void * dm_zalloc_wrapper ( size_t s , const char * file , int line )
{
return dm_zalloc_aux_debug ( s , file , line ) ;
}
char * dm_strdup_wrapper ( const char * str , const char * file , int line )
{
return dm_strdup_aux ( str , file , line ) ;
}
void dm_free_wrapper ( void * ptr )
{
dm_free_aux ( ptr ) ;
}
void * dm_realloc_wrapper ( void * p , unsigned int s , const char * file , int line )
{
return dm_realloc_aux ( p , s , file , line ) ;
}
int dm_dump_memory_wrapper ( void )
{
return dm_dump_memory_debug ( ) ;
}
void dm_bounds_check_wrapper ( void )
{
dm_bounds_check_debug ( ) ;
}
# else /* !DEBUG_MEM */
void * dm_malloc_wrapper ( size_t s , const char * file , int line )
{
return dm_malloc_aux ( s , file , line ) ;
}
void * dm_zalloc_wrapper ( size_t s , const char * file , int line )
{
return dm_zalloc_aux ( s , file , line ) ;
}
char * dm_strdup_wrapper ( const char * str ,
const char * file __attribute__ ( ( unused ) ) ,
int line __attribute__ ( ( unused ) ) )
{
return strdup ( str ) ;
}
void dm_free_wrapper ( void * ptr )
{
free ( ptr ) ;
}
void * dm_realloc_wrapper ( void * p , unsigned int s ,
const char * file __attribute__ ( ( unused ) ) ,
int line __attribute__ ( ( unused ) ) )
{
return realloc ( p , s ) ;
}
int dm_dump_memory_wrapper ( void )
{
return 1 ;
}
void dm_bounds_check_wrapper ( void )
{
}
# endif /* DEBUG_MEM */