📄 ftdbgmem.c
字号:
node->hash = hash;
*pnode = node;
Exit:
return node;
}
static void
ft_mem_table_set( FT_MemTable table,
FT_Byte* address,
FT_ULong size,
FT_Long delta )
{
FT_MemNode *pnode, node;
if ( table )
{
FT_MemSource source;
pnode = ft_mem_table_get_nodep( table, address );
node = *pnode;
if ( node )
{
if ( node->size < 0 )
{
/* This block was already freed. Our memory is now completely */
/* corrupted! */
/* This can only happen in keep-alive mode. */
ft_mem_debug_panic(
"memory heap corrupted (allocating freed block)" );
}
else
{
/* This block was already allocated. This means that our memory */
/* is also corrupted! */
ft_mem_debug_panic(
"memory heap corrupted (re-allocating allocated block at"
" %p, of size %ld)\n"
"org=%s:%d new=%s:%d\n",
node->address, node->size,
FT_FILENAME( node->source->file_name ), node->source->line_no,
FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
}
}
/* we need to create a new node in this table */
node = (FT_MemNode)ft_mem_table_alloc( table, sizeof ( *node ) );
if ( node == NULL )
ft_mem_debug_panic( "not enough memory to run memory tests" );
node->address = address;
node->size = size;
node->source = source = ft_mem_table_get_source( table );
if ( delta == 0 )
{
/* this is an allocation */
source->all_blocks++;
source->cur_blocks++;
if ( source->cur_blocks > source->max_blocks )
source->max_blocks = source->cur_blocks;
}
if ( size > (FT_ULong)source->cur_max )
source->cur_max = size;
if ( delta != 0 )
{
/* we are growing or shrinking a reallocated block */
source->cur_size += delta;
table->alloc_current += delta;
}
else
{
/* we are allocating a new block */
source->cur_size += size;
table->alloc_current += size;
}
source->all_size += size;
if ( source->cur_size > source->max_size )
source->max_size = source->cur_size;
node->free_file_name = NULL;
node->free_line_no = 0;
node->link = pnode[0];
pnode[0] = node;
table->nodes++;
table->alloc_total += size;
if ( table->alloc_current > table->alloc_max )
table->alloc_max = table->alloc_current;
if ( table->nodes * 3 < table->size ||
table->size * 3 < table->nodes )
ft_mem_table_resize( table );
}
}
static void
ft_mem_table_remove( FT_MemTable table,
FT_Byte* address,
FT_Long delta )
{
if ( table )
{
FT_MemNode *pnode, node;
pnode = ft_mem_table_get_nodep( table, address );
node = *pnode;
if ( node )
{
FT_MemSource source;
if ( node->size < 0 )
ft_mem_debug_panic(
"freeing memory block at %p more than once at (%s:%ld)\n"
"block allocated at (%s:%ld) and released at (%s:%ld)",
address,
FT_FILENAME( _ft_debug_file ), _ft_debug_lineno,
FT_FILENAME( node->source->file_name ), node->source->line_no,
FT_FILENAME( node->free_file_name ), node->free_line_no );
/* scramble the node's content for additional safety */
FT_MEM_SET( address, 0xF3, node->size );
if ( delta == 0 )
{
source = node->source;
source->cur_blocks--;
source->cur_size -= node->size;
table->alloc_current -= node->size;
}
if ( table->keep_alive )
{
/* we simply invert the node's size to indicate that the node */
/* was freed. */
node->size = -node->size;
node->free_file_name = _ft_debug_file;
node->free_line_no = _ft_debug_lineno;
}
else
{
table->nodes--;
*pnode = node->link;
node->size = 0;
node->source = NULL;
ft_mem_table_free( table, node );
if ( table->nodes * 3 < table->size ||
table->size * 3 < table->nodes )
ft_mem_table_resize( table );
}
}
else
ft_mem_debug_panic(
"trying to free unknown block at %p in (%s:%ld)\n",
address,
FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
}
}
extern FT_Pointer
ft_mem_debug_alloc( FT_Memory memory,
FT_Long size )
{
FT_MemTable table = (FT_MemTable)memory->user;
FT_Byte* block;
if ( size <= 0 )
ft_mem_debug_panic( "negative block size allocation (%ld)", size );
/* return NULL if the maximum number of allocations was reached */
if ( table->bound_count &&
table->alloc_count >= table->alloc_count_max )
return NULL;
/* return NULL if this allocation would overflow the maximum heap size */
if ( table->bound_total &&
table->alloc_total_max - table->alloc_current > (FT_ULong)size )
return NULL;
block = (FT_Byte *)ft_mem_table_alloc( table, size );
if ( block )
{
ft_mem_table_set( table, block, (FT_ULong)size, 0 );
table->alloc_count++;
}
_ft_debug_file = "<unknown>";
_ft_debug_lineno = 0;
return (FT_Pointer)block;
}
extern void
ft_mem_debug_free( FT_Memory memory,
FT_Pointer block )
{
FT_MemTable table = (FT_MemTable)memory->user;
if ( block == NULL )
ft_mem_debug_panic( "trying to free NULL in (%s:%ld)",
FT_FILENAME( _ft_debug_file ),
_ft_debug_lineno );
ft_mem_table_remove( table, (FT_Byte*)block, 0 );
if ( !table->keep_alive )
ft_mem_table_free( table, block );
table->alloc_count--;
_ft_debug_file = "<unknown>";
_ft_debug_lineno = 0;
}
extern FT_Pointer
ft_mem_debug_realloc( FT_Memory memory,
FT_Long cur_size,
FT_Long new_size,
FT_Pointer block )
{
FT_MemTable table = (FT_MemTable)memory->user;
FT_MemNode node, *pnode;
FT_Pointer new_block;
FT_Long delta;
const char* file_name = FT_FILENAME( _ft_debug_file );
FT_Long line_no = _ft_debug_lineno;
/* unlikely, but possible */
if ( new_size == cur_size )
return block;
/* the following is valid according to ANSI C */
#if 0
if ( block == NULL || cur_size == 0 )
ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)",
file_name, line_no );
#endif
/* while the following is allowed in ANSI C also, we abort since */
/* such case should be handled by FreeType. */
if ( new_size <= 0 )
ft_mem_debug_panic(
"trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)",
block, cur_size, file_name, line_no );
/* check `cur_size' value */
pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block );
node = *pnode;
if ( !node )
ft_mem_debug_panic(
"trying to reallocate unknown block at %p in (%s:%ld)",
block, file_name, line_no );
if ( node->size <= 0 )
ft_mem_debug_panic(
"trying to reallocate freed block at %p in (%s:%ld)",
block, file_name, line_no );
if ( node->size != cur_size )
ft_mem_debug_panic( "invalid ft_realloc request for %p. cur_size is "
"%ld instead of %ld in (%s:%ld)",
block, cur_size, node->size, file_name, line_no );
/* return NULL if the maximum number of allocations was reached */
if ( table->bound_count &&
table->alloc_count >= table->alloc_count_max )
return NULL;
delta = (FT_Long)( new_size - cur_size );
/* return NULL if this allocation would overflow the maximum heap size */
if ( delta > 0 &&
table->bound_total &&
table->alloc_current + (FT_ULong)delta > table->alloc_total_max )
return NULL;
new_block = (FT_Byte *)ft_mem_table_alloc( table, new_size );
if ( new_block == NULL )
return NULL;
ft_mem_table_set( table, (FT_Byte*)new_block, new_size, delta );
ft_memcpy( new_block, block, cur_size < new_size ? cur_size : new_size );
ft_mem_table_remove( table, (FT_Byte*)block, delta );
_ft_debug_file = "<unknown>";
_ft_debug_lineno = 0;
if ( !table->keep_alive )
ft_mem_table_free( table, block );
return new_block;
}
extern FT_Int
ft_mem_debug_init( FT_Memory memory )
{
FT_MemTable table;
FT_Int result = 0;
if ( getenv( "FT2_DEBUG_MEMORY" ) )
{
table = ft_mem_table_new( memory );
if ( table )
{
const char* p;
memory->user = table;
memory->alloc = ft_mem_debug_alloc;
memory->realloc = ft_mem_debug_realloc;
memory->free = ft_mem_debug_free;
p = getenv( "FT2_ALLOC_TOTAL_MAX" );
if ( p != NULL )
{
FT_Long total_max = ft_atol( p );
if ( total_max > 0 )
{
table->bound_total = 1;
table->alloc_total_max = (FT_ULong)total_max;
}
}
p = getenv( "FT2_ALLOC_COUNT_MAX" );
if ( p != NULL )
{
FT_Long total_count = ft_atol( p );
if ( total_count > 0 )
{
table->bound_count = 1;
table->alloc_count_max = (FT_ULong)total_count;
}
}
p = getenv( "FT2_KEEP_ALIVE" );
if ( p != NULL )
{
FT_Long keep_alive = ft_atol( p );
if ( keep_alive > 0 )
table->keep_alive = 1;
}
result = 1;
}
}
return result;
}
extern void
ft_mem_debug_done( FT_Memory memory )
{
FT_MemTable table = (FT_MemTable)memory->user;
if ( table )
{
memory->free = table->free;
memory->realloc = table->realloc;
memory->alloc = table->alloc;
ft_mem_table_destroy( table );
memory->user = NULL;
}
}
static int
ft_mem_source_compare( const void* p1,
const void* p2 )
{
FT_MemSource s1 = *(FT_MemSource*)p1;
FT_MemSource s2 = *(FT_MemSource*)p2;
if ( s2->max_size > s1->max_size )
return 1;
else if ( s2->max_size < s1->max_size )
return -1;
else
return 0;
}
extern void
FT_DumpMemory( FT_Memory memory )
{
FT_MemTable table = (FT_MemTable)memory->user;
if ( table )
{
FT_MemSource* bucket = table->sources;
FT_MemSource* limit = bucket + FT_MEM_SOURCE_BUCKETS;
FT_MemSource* sources;
FT_UInt nn, count;
const char* fmt;
count = 0;
for ( ; bucket < limit; bucket++ )
{
FT_MemSource source = *bucket;
for ( ; source; source = source->link )
count++;
}
sources = (FT_MemSource*)ft_mem_table_alloc(
table, sizeof ( *sources ) * count );
count = 0;
for ( bucket = table->sources; bucket < limit; bucket++ )
{
FT_MemSource source = *bucket;
for ( ; source; source = source->link )
sources[count++] = source;
}
ft_qsort( sources, count, sizeof ( *sources ), ft_mem_source_compare );
printf( "FreeType Memory Dump: "
"current=%ld max=%ld total=%ld count=%ld\n",
table->alloc_current, table->alloc_max,
table->alloc_total, table->alloc_count );
printf( " block block sizes sizes sizes source\n" );
printf( " count high sum highsum max location\n" );
printf( "-------------------------------------------------\n" );
fmt = "%6ld %6ld %8ld %8ld %8ld %s:%d\n";
for ( nn = 0; nn < count; nn++ )
{
FT_MemSource source = sources[nn];
printf( fmt,
source->cur_blocks, source->max_blocks,
source->cur_size, source->max_size, source->cur_max,
FT_FILENAME( source->file_name ),
source->line_no );
}
printf( "------------------------------------------------\n" );
ft_mem_table_free( table, sources );
}
}
#else /* !FT_DEBUG_MEMORY */
/* ANSI C doesn't like empty source files */
const FT_Byte _debug_mem_dummy = 0;
#endif /* !FT_DEBUG_MEMORY */
/* END */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -