@ -93,116 +93,166 @@ static mempool_t *Mem_FindPool( poolhandle_t poolptr )
@@ -93,116 +93,166 @@ static mempool_t *Mem_FindPool( poolhandle_t poolptr )
}
# endif
void * _Mem_Alloc ( poolhandle_t poolptr , size_t size , qboolean clear , const char * filename , int filelin e )
static inline void Mem_PoolAdd ( mempool_t * pool , size_t siz e )
{
memheader_t * mem ;
mempool_t * pool ;
if ( size < = 0 )
return NULL ;
pool - > totalsize + = size ;
pool - > realsize + = sizeof ( memheader_t ) + size + sizeof ( byte ) ;
}
if ( ! poolptr )
static inline void Mem_PoolSubtract ( mempool_t * pool , size_t size )
{
Sys_Error ( " Mem_Alloc: pool == NULL (alloc at %s:%i) \n " , filename , fileline ) ;
return NULL ;
pool - > totalsize - = size ;
pool - > realsize - = sizeof ( memheader_t ) + size + sizeof ( byte ) ;
}
pool = Mem_FindPool ( poolptr ) ;
pool - > totalsize + = size ;
static inline void Mem_PoolLinkAlloc ( mempool_t * pool , memheader_t * mem )
{
mem - > next = pool - > chain ;
if ( mem - > next ) mem - > next - > prev = mem ;
pool - > chain = mem ;
mem - > prev = NULL ;
mem - > pool = pool ;
}
// big allocations are not clumped
pool - > realsize + = sizeof ( memheader_t ) + size + sizeof ( size_t ) ;
mem = ( memheader_t * ) Q_malloc ( sizeof ( memheader_t ) + size + sizeof ( size_t ) ) ;
if ( mem = = NULL )
static inline void Mem_PoolUnlinkAlloc ( mempool_t * pool , memheader_t * mem )
{
Sys_Error ( " Mem_Realloc: out of memory (alloc size %s at %s:%i) \n " , Q_memprint ( size ) , filename , fileline ) ;
return NULL ;
if ( mem - > next ) mem - > next - > prev = mem - > prev ;
if ( mem - > prev ) mem - > prev - > next = mem - > next ;
else pool - > chain = mem - > next ;
mem - > pool = NULL ;
}
static inline void Mem_InitAlloc ( memheader_t * mem , size_t size , const char * filename , int fileline )
{
mem - > size = size ;
mem - > filename = filename ;
mem - > fileline = fileline ;
mem - > size = size ;
mem - > pool = pool ;
mem - > sentinel1 = MEMHEADER_SENTINEL1 ;
// we have to use only a single byte for this sentinel, because it may not be aligned
// and some platforms can't use unaligned accesses
* ( ( byte * ) mem + sizeof ( memheader_t ) + mem - > size ) = MEMHEADER_SENTINEL2 ;
// append to head of list
mem - > next = pool - > chain ;
mem - > prev = NULL ;
pool - > chain = mem ;
if ( mem - > next ) mem - > next - > prev = mem ;
if ( clear )
memset ( ( void * ) ( ( byte * ) mem + sizeof ( memheader_t ) ) , 0 , mem - > size ) ;
return ( void * ) ( ( byte * ) mem + sizeof ( memheader_t ) ) ;
}
static const char * Mem_CheckFilename ( const char * filename )
{
static const char * dummy = " <corrupted> \0 " ;
const char * out = filename ;
int i ;
if ( ! COM_CheckString ( out ) )
if ( ! COM_CheckString ( filename ) )
return dummy ;
for ( i = 0 ; i < MAX_OSPATH ; i + + , out + + )
{
if ( * out = = ' \0 ' )
return filename ; // valid name
}
if ( memchr ( filename , ' \0 ' , MAX_OSPATH ) ! = NULL )
return filename ;
return dummy ;
}
static void Mem_FreeBlock ( memheader_t * mem , const char * filename , int fileline )
static qboolean Mem_CheckAllocHeader ( const char * func , const memheader_t * mem , const char * filename , int fileline )
{
mempool_t * pool ;
const char * memfilename ;
if ( mem - > sentinel1 ! = MEMHEADER_SENTINEL1 )
{
mem - > filename = Mem_CheckFilename ( mem - > filename ) ; // make sure what we don't crash var_args
Sys_Error ( " Mem_Free: trashed header sentinel 1 (alloc at %s:%i, free at %s:%i) \n " , mem - > filename , mem - > fileline , filename , fileline ) ;
memfilename = Mem_CheckFilename ( mem - > filename ) ;
Sys_Error ( " %s: trashed header sentinel 1 (alloc at %s:%i, check at %s:%i) \n " , func , memfilename , mem - > fileline , filename , fileline ) ;
return false ;
}
if ( * ( ( byte * ) mem + sizeof ( memheader_t ) + mem - > size ) ! = MEMHEADER_SENTINEL2 )
{
mem - > filename = Mem_CheckFilename ( mem - > filename ) ; // make sure what we don't crash var_args
Sys_Error ( " Mem_Free: trashed header sentinel 2 (alloc at %s:%i, free at %s:%i) \n " , mem - > filename , mem - > fileline , filename , fileline ) ;
memfilename = Mem_CheckFilename ( mem - > filename ) ; // make sure what we don't crash var_args
Sys_Error ( " %s: trashed header sentinel 2 (alloc at %s:%i, check at %s:%i) \n " , func , memfilename , mem - > fileline , filename , fileline ) ;
return false ;
}
return true ;
}
static qboolean Mem_CheckPool ( const char * func , const mempool_t * pool , const char * filename , int fileline )
{
if ( pool - > sentinel1 ! = MEMHEADER_SENTINEL1 )
{
Sys_Error ( " %s: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i) \n " , func , pool - > filename , pool - > fileline , filename , fileline ) ;
return false ;
}
if ( pool - > sentinel2 ! = MEMHEADER_SENTINEL1 )
{
Sys_Error ( " %s: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i) \n " , func , pool - > filename , pool - > fileline , filename , fileline ) ;
return false ;
}
return true ;
}
void * _Mem_Alloc ( poolhandle_t poolptr , size_t size , qboolean clear , const char * filename , int fileline )
{
memheader_t * mem ;
mempool_t * pool ;
if ( size < = 0 )
return NULL ;
if ( ! poolptr )
{
Sys_Error ( " %s: pool == NULL (alloc at %s:%i) \n " , __func__ , filename , fileline ) ;
return NULL ;
}
mem = ( memheader_t * ) Q_malloc ( sizeof ( memheader_t ) + size + sizeof ( byte ) ) ;
if ( mem = = NULL )
{
Sys_Error ( " %s: out of memory (alloc size %s at %s:%i) \n " , __func__ , Q_memprint ( size ) , filename , fileline ) ;
return NULL ;
}
Mem_InitAlloc ( mem , size , filename , fileline ) ;
pool = Mem_FindPool ( poolptr ) ;
Mem_PoolAdd ( pool , size ) ;
Mem_PoolLinkAlloc ( pool , mem ) ;
if ( clear )
memset ( ( void * ) ( ( byte * ) mem + sizeof ( memheader_t ) ) , 0 , mem - > size ) ;
return ( void * ) ( ( byte * ) mem + sizeof ( memheader_t ) ) ;
}
static void Mem_FreeBlock ( memheader_t * mem , const char * filename , int fileline )
{
mempool_t * pool ;
if ( ! Mem_CheckAllocHeader ( __func__ , mem , filename , fileline ) )
return ;
pool = mem - > pool ;
// unlink memheader from doubly linked list
if ( ( mem - > prev ? mem - > prev - > next ! = mem : pool - > chain ! = mem ) | | ( mem - > next & & mem - > next - > prev ! = mem ) )
Sys_Error ( " Mem_Free: not allocated or double freed (free at %s:%i) \n " , filename , fileline ) ;
if ( mem - > prev ) mem - > prev - > next = mem - > next ;
else pool - > chain = mem - > next ;
if ( mem - > next )
mem - > next - > prev = mem - > prev ;
{
Sys_Error ( " %s: not allocated or double freed (free at %s:%i) \n " , __func__ , filename , fileline ) ;
return ;
}
// memheader has been unlinked, do the actual free now
pool - > totalsize - = mem - > size ;
Mem_PoolSubtract ( pool , mem - > size ) ;
Mem_PoolUnlinkAlloc ( pool , mem ) ;
pool - > realsize - = sizeof ( memheader_t ) + mem - > size + sizeof ( size_t ) ;
Q_free ( mem ) ;
}
void _Mem_Free ( void * data , const char * filename , int fileline )
{
if ( data = = NULL ) Sys_Error ( " Mem_Free: data == NULL (called at %s:%i) \n " , filename , fileline ) ;
if ( data = = NULL )
{
Sys_Error ( " Mem_Free: data == NULL (called at %s:%i) \n " , filename , fileline ) ;
return ;
}
Mem_FreeBlock ( ( memheader_t * ) ( ( byte * ) data - sizeof ( memheader_t ) ) , filename , fileline ) ;
}
void * _Mem_Realloc ( poolhandle_t poolptr , void * data , size_t size , qboolean clear , const char * filename , int fileline )
{
memheader_t * mem ;
mempool_t * pool , * oldpool ;
size_t newsize , oldsize ;
char * nb ;
mempool_t * pool ;
size_t oldsize ;
if ( size < = 0 )
return data ; // no need to reallocate
@ -218,87 +268,51 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
@@ -218,87 +268,51 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
mem = ( memheader_t * ) ( ( byte * ) data - sizeof ( memheader_t ) ) ;
if ( mem - > sentinel1 ! = MEMHEADER_SENTINEL1 )
{
mem - > filename = Mem_CheckFilename ( mem - > filename ) ; // make sure what we don't crash var_args
Sys_Error ( " Mem_Realloc: trashed header sentinel 1 (alloc at %s:%i, realloc at %s:%i) \n " , mem - > filename , mem - > fileline , filename , fileline ) ;
return NULL ;
}
if ( * ( ( byte * ) mem + sizeof ( memheader_t ) + mem - > size ) ! = MEMHEADER_SENTINEL2 )
{
mem - > filename = Mem_CheckFilename ( mem - > filename ) ; // make sure what we don't crash var_args
Sys_Error ( " Mem_Realloc: trashed header sentinel 2 (alloc at %s:%i, realloc at %s:%i) \n " , mem - > filename , mem - > fileline , filename , fileline ) ;
if ( ! Mem_CheckAllocHeader ( " Mem_Realloc " , mem , filename , fileline ) )
return NULL ;
}
oldsize = mem - > size ;
oldpool = mem - > pool ;
if ( size = = oldsize )
return data ;
# if XASH_CUSTOM_SWAP
nb = _Mem_Alloc ( poolptr , size , clear , filename , fileline ) ;
{
char * nb = _Mem_Alloc ( poolptr , size , clear , filename , fileline ) ;
newsize = mem - > size < size ? mem - > size : size ; // upper data can be trucnated!
size_t newsize = mem - > size < size ? mem - > size : size ; // upper data can be trucnated!
memcpy ( nb , data , newsize ) ;
_Mem_Free ( data , filename , fileline ) ; // free unused old block
return nb ;
}
# else // XASH_CUSTOM_SWAP
pool = Mem_FindPool ( poolptr ) ;
mem = realloc ( mem , sizeof ( memheader_t ) + size + sizeof ( size_t ) ) ;
mem = realloc ( mem , sizeof ( memheader_t ) + size + sizeof ( byte ) ) ;
if ( mem = = NULL )
{
Sys_Error ( " Mem_Realloc: out of memory (alloc size %s at %s:%i) \n " , Q_memprint ( size ) , filename , fileline ) ;
return NULL ;
}
pool - > totalsize - = oldsize ;
pool - > realsize - = sizeof ( memheader_t ) + oldsize + sizeof ( size_t ) ;
pool - > totalsize + = size ;
pool - > realsize + = sizeof ( memheader_t ) + size + sizeof ( size_t ) ;
mem - > filename = filename ;
mem - > fileline = fileline ;
mem - > size = size ;
Mem_PoolSubtract ( pool , oldsize ) ;
Mem_PoolAdd ( pool , size ) ;
Mem_InitAlloc ( mem , size , filename , fileline ) ;
// if allocation was migrated from one pool to another
// (this is possible with original Mem_Realloc func)
if ( old pool ! = pool )
if ( unlikely ( mem - > pool ! = pool ) )
{
// unlink from old pool
if ( mem - > prev )
mem - > prev - > next = mem - > next ;
else pool - > chain = mem - > next ;
if ( mem - > next )
mem - > next - > prev = mem - > prev ;
// attach to new
mem - > next = pool - > chain ;
mem - > prev = NULL ;
pool - > chain = mem ;
if ( mem - > next )
mem - > next - > prev = mem ;
Mem_PoolUnlinkAlloc ( mem - > pool , mem ) ;
Mem_PoolLinkAlloc ( pool , mem ) ;
}
else
{
// simply update pointers
if ( mem - > prev )
mem - > prev - > next = mem ;
if ( mem - > next ) mem - > next - > prev = mem ;
if ( mem - > prev ) mem - > prev - > next = mem ;
else pool - > chain = mem ;
if ( mem - > next )
mem - > next - > prev = mem ;
}
mem - > sentinel1 = MEMHEADER_SENTINEL1 ;
// we have to use only a single byte for this sentinel, because it may not be aligned
// and some platforms can't use unaligned accesses
* ( ( byte * ) mem + sizeof ( memheader_t ) + mem - > size ) = MEMHEADER_SENTINEL2 ;
// clear new memory
if ( clear & & size > oldsize )
memset ( ( byte * ) mem + sizeof ( memheader_t ) + oldsize , 0 , size - oldsize ) ;
@ -349,8 +363,7 @@ void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
@@ -349,8 +363,7 @@ void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
// unlink pool from chain
for ( chainaddress = & poolchain ; * chainaddress & & * chainaddress ! = pool ; chainaddress = & ( ( * chainaddress ) - > next ) ) ;
if ( * chainaddress ! = pool ) Sys_Error ( " Mem_FreePool: pool already free (freepool at %s:%i) \n " , filename , fileline ) ;
if ( pool - > sentinel1 ! = MEMHEADER_SENTINEL1 ) Sys_Error ( " Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i) \n " , pool - > filename , pool - > fileline , filename , fileline ) ;
if ( pool - > sentinel2 ! = MEMHEADER_SENTINEL1 ) Sys_Error ( " Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i) \n " , pool - > filename , pool - > fileline , filename , fileline ) ;
Mem_CheckPool ( " Mem_FreePool " , pool , filename , fileline ) ;
* chainaddress = pool - > next ;
// free memory owned by the pool
@ -367,8 +380,7 @@ void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
@@ -367,8 +380,7 @@ void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
mempool_t * pool = Mem_FindPool ( poolptr ) ;
if ( ! poolptr ) Sys_Error ( " Mem_EmptyPool: pool == NULL (emptypool at %s:%i) \n " , filename , fileline ) ;
if ( pool - > sentinel1 ! = MEMHEADER_SENTINEL1 ) Sys_Error ( " Mem_EmptyPool: trashed pool sentinel 1 (allocpool at %s:%i, emptypool at %s:%i) \n " , pool - > filename , pool - > fileline , filename , fileline ) ;
if ( pool - > sentinel2 ! = MEMHEADER_SENTINEL1 ) Sys_Error ( " Mem_EmptyPool: trashed pool sentinel 2 (allocpool at %s:%i, emptypool at %s:%i) \n " , pool - > filename , pool - > fileline , filename , fileline ) ;
Mem_CheckPool ( " Mem_FreePool " , pool , filename , fileline ) ;
// free memory owned by the pool
while ( pool - > chain ) Mem_FreeBlock ( pool - > chain , filename , fileline ) ;
@ -383,15 +395,20 @@ static qboolean Mem_CheckAlloc( mempool_t *pool, void *data )
@@ -383,15 +395,20 @@ static qboolean Mem_CheckAlloc( mempool_t *pool, void *data )
// search only one pool
target = ( memheader_t * ) ( ( byte * ) data - sizeof ( memheader_t ) ) ;
for ( header = pool - > chain ; header ; header = header - > next )
if ( header = = target ) return true ;
{
if ( header = = target )
return true ;
}
}
else
{
// search all pools
for ( pool = poolchain ; pool ; pool = pool - > next )
{
if ( Mem_CheckAlloc ( pool , data ) )
return true ;
}
}
return false ;
}
@ -403,31 +420,11 @@ Check pointer for memory
@@ -403,31 +420,11 @@ Check pointer for memory
qboolean Mem_IsAllocatedExt ( poolhandle_t poolptr , void * data )
{
mempool_t * pool = NULL ;
if ( poolptr ) pool = Mem_FindPool ( poolptr ) ;
return Mem_CheckAlloc ( pool , data ) ;
}
static void Mem_CheckHeaderSentinels ( void * data , const char * filename , int fileline )
{
memheader_t * mem ;
if ( data = = NULL )
Sys_Error ( " Mem_CheckSentinels: data == NULL (sentinel check at %s:%i) \n " , filename , fileline ) ;
mem = ( memheader_t * ) ( ( byte * ) data - sizeof ( memheader_t ) ) ;
if ( mem - > sentinel1 ! = MEMHEADER_SENTINEL1 )
{
mem - > filename = Mem_CheckFilename ( mem - > filename ) ; // make sure what we don't crash var_args
Sys_Error ( " Mem_CheckSentinels: trashed header sentinel 1 (block allocated at %s:%i, sentinel check at %s:%i) \n " , mem - > filename , mem - > fileline , filename , fileline ) ;
}
if ( poolptr )
pool = Mem_FindPool ( poolptr ) ;
if ( * ( ( byte * ) mem + sizeof ( memheader_t ) + mem - > size ) ! = MEMHEADER_SENTINEL2 )
{
mem - > filename = Mem_CheckFilename ( mem - > filename ) ; // make sure what we don't crash var_args
Sys_Error ( " Mem_CheckSentinels: trashed header sentinel 2 (block allocated at %s:%i, sentinel check at %s:%i) \n " , mem - > filename , mem - > fileline , filename , fileline ) ;
}
return Mem_CheckAlloc ( pool , data ) ;
}
void _Mem_Check ( const char * filename , int fileline )
@ -436,16 +433,11 @@ void _Mem_Check( const char *filename, int fileline )
@@ -436,16 +433,11 @@ void _Mem_Check( const char *filename, int fileline )
mempool_t * pool ;
for ( pool = poolchain ; pool ; pool = pool - > next )
{
if ( pool - > sentinel1 ! = MEMHEADER_SENTINEL1 )
Sys_Error ( " Mem_CheckSentinelsGlobal: trashed pool sentinel 1 (allocpool at %s:%i, sentinel check at %s:%i) \n " , pool - > filename , pool - > fileline , filename , fileline ) ;
if ( pool - > sentinel2 ! = MEMHEADER_SENTINEL1 )
Sys_Error ( " Mem_CheckSentinelsGlobal: trashed pool sentinel 2 (allocpool at %s:%i, sentinel check at %s:%i) \n " , pool - > filename , pool - > fileline , filename , fileline ) ;
}
Mem_CheckPool ( " Mem_CheckSentinels " , pool , filename , fileline ) ;
for ( pool = poolchain ; pool ; pool = pool - > next )
for ( mem = pool - > chain ; mem ; mem = mem - > next )
Mem_CheckHeaderSentinels ( ( void * ) ( ( byte * ) mem + sizeof ( memheader_t ) ) , filename , fileline ) ;
Mem_CheckAllocHeader ( " Mem_CheckSentinels " , mem , filename , fileline ) ;
}
void Mem_PrintStats ( void )
@ -472,30 +464,33 @@ void Mem_PrintList( size_t minallocationsize )
@@ -472,30 +464,33 @@ void Mem_PrintList( size_t minallocationsize )
Mem_Check ( ) ;
Con_Printf ( " memory pool list: \n " " ^3size name \n " ) ;
Con_Printf ( " memory pool list: \n " ) ;
Con_Printf ( " \t ^3size \t \t \t \t name \n " ) ;
for ( pool = poolchain ; pool ; pool = pool - > next )
{
long changed_size = ( long ) pool - > totalsize - ( long ) pool - > lastchecksize ;
// poolnames can contain color symbols, make sure what color is reset
if ( changed_size ! = 0 )
if ( pool - > lastchecksize ! = 0 & & changed_size ! = 0 )
{
char sign = ( changed_size < 0 ) ? ' - ' : ' + ' ;
Con_Printf ( " %10s (%10s actual) %s (^7%c%s change) \n " , Q_memprint ( pool - > totalsize ) , Q_memprint ( pool - > realsize ) ,
Con_Printf ( " %10s (%10s real) \t %s (^7%c%s change) \n " , Q_memprint ( pool - > totalsize ) , Q_memprint ( pool - > realsize ) ,
pool - > name , sign , Q_memprint ( abs ( changed_size ) ) ) ;
}
else
{
Con_Printf ( " %5s (%5s actual) %s \n " , Q_memprint ( pool - > totalsize ) , Q_memprint ( pool - > realsize ) , pool - > name ) ;
Con_Printf ( " %10s (%10s real) \t %s \n " , Q_memprint ( pool - > totalsize ) , Q_memprint ( pool - > realsize ) , pool - > name ) ;
}
pool - > lastchecksize = pool - > totalsize ;
for ( mem = pool - > chain ; mem ; mem = mem - > next )
{
if ( mem - > size > = minallocationsize )
Con_Printf ( " %10s allocated at %s:%i \n " , Q_memprint ( mem - > size ) , mem - > filename , mem - > fileline ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =