1*37da2899SCharles.Forsyth /***************************************************************************/ 2*37da2899SCharles.Forsyth /* */ 3*37da2899SCharles.Forsyth /* ftdbgmem.c */ 4*37da2899SCharles.Forsyth /* */ 5*37da2899SCharles.Forsyth /* Memory debugger (body). */ 6*37da2899SCharles.Forsyth /* */ 7*37da2899SCharles.Forsyth /* Copyright 2001, 2002 by */ 8*37da2899SCharles.Forsyth /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 9*37da2899SCharles.Forsyth /* */ 10*37da2899SCharles.Forsyth /* This file is part of the FreeType project, and may only be used, */ 11*37da2899SCharles.Forsyth /* modified, and distributed under the terms of the FreeType project */ 12*37da2899SCharles.Forsyth /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 13*37da2899SCharles.Forsyth /* this file you indicate that you have read the license and */ 14*37da2899SCharles.Forsyth /* understand and accept it fully. */ 15*37da2899SCharles.Forsyth /* */ 16*37da2899SCharles.Forsyth /***************************************************************************/ 17*37da2899SCharles.Forsyth 18*37da2899SCharles.Forsyth 19*37da2899SCharles.Forsyth #include <ft2build.h> 20*37da2899SCharles.Forsyth #include FT_CONFIG_CONFIG_H 21*37da2899SCharles.Forsyth #include FT_INTERNAL_DEBUG_H 22*37da2899SCharles.Forsyth #include FT_INTERNAL_MEMORY_H 23*37da2899SCharles.Forsyth #include FT_SYSTEM_H 24*37da2899SCharles.Forsyth #include FT_ERRORS_H 25*37da2899SCharles.Forsyth #include FT_TYPES_H 26*37da2899SCharles.Forsyth 27*37da2899SCharles.Forsyth 28*37da2899SCharles.Forsyth #ifdef FT_DEBUG_MEMORY 29*37da2899SCharles.Forsyth 30*37da2899SCharles.Forsyth 31*37da2899SCharles.Forsyth #include <stdio.h> 32*37da2899SCharles.Forsyth #include <stdlib.h> 33*37da2899SCharles.Forsyth 34*37da2899SCharles.Forsyth 35*37da2899SCharles.Forsyth typedef struct FT_MemNodeRec_* FT_MemNode; 36*37da2899SCharles.Forsyth typedef struct FT_MemTableRec_* FT_MemTable; 37*37da2899SCharles.Forsyth 38*37da2899SCharles.Forsyth #define FT_MEM_VAL( addr ) ((FT_ULong)(FT_Pointer)( addr )) 39*37da2899SCharles.Forsyth 40*37da2899SCharles.Forsyth typedef struct FT_MemNodeRec_ 41*37da2899SCharles.Forsyth { 42*37da2899SCharles.Forsyth FT_Byte* address; 43*37da2899SCharles.Forsyth FT_Long size; /* < 0 if the block was freed */ 44*37da2899SCharles.Forsyth 45*37da2899SCharles.Forsyth const char* alloc_file_name; 46*37da2899SCharles.Forsyth FT_Long alloc_line_no; 47*37da2899SCharles.Forsyth 48*37da2899SCharles.Forsyth const char* free_file_name; 49*37da2899SCharles.Forsyth FT_Long free_line_no; 50*37da2899SCharles.Forsyth 51*37da2899SCharles.Forsyth FT_MemNode link; 52*37da2899SCharles.Forsyth 53*37da2899SCharles.Forsyth } FT_MemNodeRec; 54*37da2899SCharles.Forsyth 55*37da2899SCharles.Forsyth 56*37da2899SCharles.Forsyth typedef struct FT_MemTableRec_ 57*37da2899SCharles.Forsyth { 58*37da2899SCharles.Forsyth FT_ULong size; 59*37da2899SCharles.Forsyth FT_ULong nodes; 60*37da2899SCharles.Forsyth FT_MemNode* buckets; 61*37da2899SCharles.Forsyth 62*37da2899SCharles.Forsyth FT_ULong alloc_total; 63*37da2899SCharles.Forsyth FT_ULong alloc_current; 64*37da2899SCharles.Forsyth FT_ULong alloc_max; 65*37da2899SCharles.Forsyth 66*37da2899SCharles.Forsyth const char* file_name; 67*37da2899SCharles.Forsyth FT_Long line_no; 68*37da2899SCharles.Forsyth 69*37da2899SCharles.Forsyth FT_Memory memory; 70*37da2899SCharles.Forsyth FT_Pointer memory_user; 71*37da2899SCharles.Forsyth FT_Alloc_Func alloc; 72*37da2899SCharles.Forsyth FT_Free_Func free; 73*37da2899SCharles.Forsyth FT_Realloc_Func realloc; 74*37da2899SCharles.Forsyth 75*37da2899SCharles.Forsyth } FT_MemTableRec; 76*37da2899SCharles.Forsyth 77*37da2899SCharles.Forsyth 78*37da2899SCharles.Forsyth #define FT_MEM_SIZE_MIN 7 79*37da2899SCharles.Forsyth #define FT_MEM_SIZE_MAX 13845163 80*37da2899SCharles.Forsyth 81*37da2899SCharles.Forsyth #define FT_FILENAME( x ) ((x) ? (x) : "unknown file") 82*37da2899SCharles.Forsyth 83*37da2899SCharles.Forsyth 84*37da2899SCharles.Forsyth static const FT_UInt ft_mem_primes[] = 85*37da2899SCharles.Forsyth { 86*37da2899SCharles.Forsyth 7, 87*37da2899SCharles.Forsyth 11, 88*37da2899SCharles.Forsyth 19, 89*37da2899SCharles.Forsyth 37, 90*37da2899SCharles.Forsyth 73, 91*37da2899SCharles.Forsyth 109, 92*37da2899SCharles.Forsyth 163, 93*37da2899SCharles.Forsyth 251, 94*37da2899SCharles.Forsyth 367, 95*37da2899SCharles.Forsyth 557, 96*37da2899SCharles.Forsyth 823, 97*37da2899SCharles.Forsyth 1237, 98*37da2899SCharles.Forsyth 1861, 99*37da2899SCharles.Forsyth 2777, 100*37da2899SCharles.Forsyth 4177, 101*37da2899SCharles.Forsyth 6247, 102*37da2899SCharles.Forsyth 9371, 103*37da2899SCharles.Forsyth 14057, 104*37da2899SCharles.Forsyth 21089, 105*37da2899SCharles.Forsyth 31627, 106*37da2899SCharles.Forsyth 47431, 107*37da2899SCharles.Forsyth 71143, 108*37da2899SCharles.Forsyth 106721, 109*37da2899SCharles.Forsyth 160073, 110*37da2899SCharles.Forsyth 240101, 111*37da2899SCharles.Forsyth 360163, 112*37da2899SCharles.Forsyth 540217, 113*37da2899SCharles.Forsyth 810343, 114*37da2899SCharles.Forsyth 1215497, 115*37da2899SCharles.Forsyth 1823231, 116*37da2899SCharles.Forsyth 2734867, 117*37da2899SCharles.Forsyth 4102283, 118*37da2899SCharles.Forsyth 6153409, 119*37da2899SCharles.Forsyth 9230113, 120*37da2899SCharles.Forsyth 13845163, 121*37da2899SCharles.Forsyth }; 122*37da2899SCharles.Forsyth 123*37da2899SCharles.Forsyth 124*37da2899SCharles.Forsyth 125*37da2899SCharles.Forsyth extern void ft_mem_debug_panic(const char * fmt,...)126*37da2899SCharles.Forsyth ft_mem_debug_panic( const char* fmt, ... ) 127*37da2899SCharles.Forsyth { 128*37da2899SCharles.Forsyth va_list ap; 129*37da2899SCharles.Forsyth 130*37da2899SCharles.Forsyth 131*37da2899SCharles.Forsyth printf( "FreeType.Debug: " ); 132*37da2899SCharles.Forsyth 133*37da2899SCharles.Forsyth va_start( ap, fmt ); 134*37da2899SCharles.Forsyth vprintf( fmt, ap ); 135*37da2899SCharles.Forsyth va_end( ap ); 136*37da2899SCharles.Forsyth 137*37da2899SCharles.Forsyth printf( "\n" ); 138*37da2899SCharles.Forsyth exit( EXIT_FAILURE ); 139*37da2899SCharles.Forsyth } 140*37da2899SCharles.Forsyth 141*37da2899SCharles.Forsyth 142*37da2899SCharles.Forsyth static FT_ULong ft_mem_closest_prime(FT_ULong num)143*37da2899SCharles.Forsyth ft_mem_closest_prime( FT_ULong num ) 144*37da2899SCharles.Forsyth { 145*37da2899SCharles.Forsyth FT_UInt i; 146*37da2899SCharles.Forsyth 147*37da2899SCharles.Forsyth 148*37da2899SCharles.Forsyth for ( i = 0; 149*37da2899SCharles.Forsyth i < sizeof ( ft_mem_primes ) / sizeof ( ft_mem_primes[0] ); i++ ) 150*37da2899SCharles.Forsyth if ( ft_mem_primes[i] > num ) 151*37da2899SCharles.Forsyth return ft_mem_primes[i]; 152*37da2899SCharles.Forsyth 153*37da2899SCharles.Forsyth return FT_MEM_SIZE_MAX; 154*37da2899SCharles.Forsyth } 155*37da2899SCharles.Forsyth 156*37da2899SCharles.Forsyth 157*37da2899SCharles.Forsyth static FT_Pointer ft_mem_table_alloc(FT_MemTable table,FT_Long size)158*37da2899SCharles.Forsyth ft_mem_table_alloc( FT_MemTable table, 159*37da2899SCharles.Forsyth FT_Long size ) 160*37da2899SCharles.Forsyth { 161*37da2899SCharles.Forsyth FT_Memory memory = table->memory; 162*37da2899SCharles.Forsyth FT_Pointer block; 163*37da2899SCharles.Forsyth 164*37da2899SCharles.Forsyth 165*37da2899SCharles.Forsyth memory->user = table->memory_user; 166*37da2899SCharles.Forsyth block = table->alloc( memory, size ); 167*37da2899SCharles.Forsyth memory->user = table; 168*37da2899SCharles.Forsyth 169*37da2899SCharles.Forsyth return block; 170*37da2899SCharles.Forsyth } 171*37da2899SCharles.Forsyth 172*37da2899SCharles.Forsyth 173*37da2899SCharles.Forsyth static void ft_mem_table_free(FT_MemTable table,FT_Pointer block)174*37da2899SCharles.Forsyth ft_mem_table_free( FT_MemTable table, 175*37da2899SCharles.Forsyth FT_Pointer block ) 176*37da2899SCharles.Forsyth { 177*37da2899SCharles.Forsyth FT_Memory memory = table->memory; 178*37da2899SCharles.Forsyth 179*37da2899SCharles.Forsyth 180*37da2899SCharles.Forsyth memory->user = table->memory_user; 181*37da2899SCharles.Forsyth table->free( memory, block ); 182*37da2899SCharles.Forsyth memory->user = table; 183*37da2899SCharles.Forsyth } 184*37da2899SCharles.Forsyth 185*37da2899SCharles.Forsyth 186*37da2899SCharles.Forsyth static void ft_mem_table_resize(FT_MemTable table)187*37da2899SCharles.Forsyth ft_mem_table_resize( FT_MemTable table ) 188*37da2899SCharles.Forsyth { 189*37da2899SCharles.Forsyth FT_ULong new_size; 190*37da2899SCharles.Forsyth 191*37da2899SCharles.Forsyth 192*37da2899SCharles.Forsyth new_size = ft_mem_closest_prime( table->nodes ); 193*37da2899SCharles.Forsyth if ( new_size != table->size ) 194*37da2899SCharles.Forsyth { 195*37da2899SCharles.Forsyth FT_MemNode* new_buckets ; 196*37da2899SCharles.Forsyth FT_ULong i; 197*37da2899SCharles.Forsyth 198*37da2899SCharles.Forsyth 199*37da2899SCharles.Forsyth new_buckets = (FT_MemNode *) 200*37da2899SCharles.Forsyth ft_mem_table_alloc( table, 201*37da2899SCharles.Forsyth new_size * sizeof ( FT_MemNode ) ); 202*37da2899SCharles.Forsyth if ( new_buckets == NULL ) 203*37da2899SCharles.Forsyth return; 204*37da2899SCharles.Forsyth 205*37da2899SCharles.Forsyth FT_MEM_ZERO( new_buckets, sizeof ( FT_MemNode ) * new_size ); 206*37da2899SCharles.Forsyth 207*37da2899SCharles.Forsyth for ( i = 0; i < table->size; i++ ) 208*37da2899SCharles.Forsyth { 209*37da2899SCharles.Forsyth FT_MemNode node, next, *pnode; 210*37da2899SCharles.Forsyth FT_ULong hash; 211*37da2899SCharles.Forsyth 212*37da2899SCharles.Forsyth 213*37da2899SCharles.Forsyth node = table->buckets[i]; 214*37da2899SCharles.Forsyth while ( node ) 215*37da2899SCharles.Forsyth { 216*37da2899SCharles.Forsyth next = node->link; 217*37da2899SCharles.Forsyth hash = FT_MEM_VAL( node->address ) % new_size; 218*37da2899SCharles.Forsyth pnode = new_buckets + hash; 219*37da2899SCharles.Forsyth 220*37da2899SCharles.Forsyth node->link = pnode[0]; 221*37da2899SCharles.Forsyth pnode[0] = node; 222*37da2899SCharles.Forsyth 223*37da2899SCharles.Forsyth node = next; 224*37da2899SCharles.Forsyth } 225*37da2899SCharles.Forsyth } 226*37da2899SCharles.Forsyth 227*37da2899SCharles.Forsyth if ( table->buckets ) 228*37da2899SCharles.Forsyth ft_mem_table_free( table, table->buckets ); 229*37da2899SCharles.Forsyth 230*37da2899SCharles.Forsyth table->buckets = new_buckets; 231*37da2899SCharles.Forsyth table->size = new_size; 232*37da2899SCharles.Forsyth } 233*37da2899SCharles.Forsyth } 234*37da2899SCharles.Forsyth 235*37da2899SCharles.Forsyth 236*37da2899SCharles.Forsyth static FT_MemTable ft_mem_table_new(FT_Memory memory)237*37da2899SCharles.Forsyth ft_mem_table_new( FT_Memory memory ) 238*37da2899SCharles.Forsyth { 239*37da2899SCharles.Forsyth FT_MemTable table; 240*37da2899SCharles.Forsyth 241*37da2899SCharles.Forsyth 242*37da2899SCharles.Forsyth table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) ); 243*37da2899SCharles.Forsyth if ( table == NULL ) 244*37da2899SCharles.Forsyth goto Exit; 245*37da2899SCharles.Forsyth 246*37da2899SCharles.Forsyth FT_MEM_ZERO( table, sizeof ( *table ) ); 247*37da2899SCharles.Forsyth 248*37da2899SCharles.Forsyth table->size = FT_MEM_SIZE_MIN; 249*37da2899SCharles.Forsyth table->nodes = 0; 250*37da2899SCharles.Forsyth 251*37da2899SCharles.Forsyth table->memory = memory; 252*37da2899SCharles.Forsyth 253*37da2899SCharles.Forsyth table->memory_user = memory->user; 254*37da2899SCharles.Forsyth 255*37da2899SCharles.Forsyth table->alloc = memory->alloc; 256*37da2899SCharles.Forsyth table->realloc = memory->realloc; 257*37da2899SCharles.Forsyth table->free = memory->free; 258*37da2899SCharles.Forsyth 259*37da2899SCharles.Forsyth table->buckets = (FT_MemNode *) 260*37da2899SCharles.Forsyth memory->alloc( memory, 261*37da2899SCharles.Forsyth table->size * sizeof ( FT_MemNode ) ); 262*37da2899SCharles.Forsyth if ( table->buckets ) 263*37da2899SCharles.Forsyth FT_MEM_ZERO( table->buckets, sizeof ( FT_MemNode ) * table->size ); 264*37da2899SCharles.Forsyth else 265*37da2899SCharles.Forsyth { 266*37da2899SCharles.Forsyth memory->free( memory, table ); 267*37da2899SCharles.Forsyth table = NULL; 268*37da2899SCharles.Forsyth } 269*37da2899SCharles.Forsyth 270*37da2899SCharles.Forsyth Exit: 271*37da2899SCharles.Forsyth return table; 272*37da2899SCharles.Forsyth } 273*37da2899SCharles.Forsyth 274*37da2899SCharles.Forsyth 275*37da2899SCharles.Forsyth static void ft_mem_table_destroy(FT_MemTable table)276*37da2899SCharles.Forsyth ft_mem_table_destroy( FT_MemTable table ) 277*37da2899SCharles.Forsyth { 278*37da2899SCharles.Forsyth FT_ULong i; 279*37da2899SCharles.Forsyth 280*37da2899SCharles.Forsyth 281*37da2899SCharles.Forsyth if ( table ) 282*37da2899SCharles.Forsyth { 283*37da2899SCharles.Forsyth FT_Long leak_count = 0; 284*37da2899SCharles.Forsyth FT_ULong leaks = 0; 285*37da2899SCharles.Forsyth 286*37da2899SCharles.Forsyth 287*37da2899SCharles.Forsyth for ( i = 0; i < table->size; i++ ) 288*37da2899SCharles.Forsyth { 289*37da2899SCharles.Forsyth FT_MemNode *pnode = table->buckets + i, next, node = *pnode; 290*37da2899SCharles.Forsyth 291*37da2899SCharles.Forsyth 292*37da2899SCharles.Forsyth while ( node ) 293*37da2899SCharles.Forsyth { 294*37da2899SCharles.Forsyth next = node->link; 295*37da2899SCharles.Forsyth node->link = 0; 296*37da2899SCharles.Forsyth 297*37da2899SCharles.Forsyth if ( node->size > 0 ) 298*37da2899SCharles.Forsyth { 299*37da2899SCharles.Forsyth printf( 300*37da2899SCharles.Forsyth "leaked memory block at address %p, size %8ld in (%s:%ld)\n", 301*37da2899SCharles.Forsyth node->address, node->size, 302*37da2899SCharles.Forsyth FT_FILENAME( node->alloc_file_name ), 303*37da2899SCharles.Forsyth node->alloc_line_no ); 304*37da2899SCharles.Forsyth 305*37da2899SCharles.Forsyth leak_count++; 306*37da2899SCharles.Forsyth leaks += node->size; 307*37da2899SCharles.Forsyth 308*37da2899SCharles.Forsyth ft_mem_table_free( table, node->address ); 309*37da2899SCharles.Forsyth } 310*37da2899SCharles.Forsyth 311*37da2899SCharles.Forsyth node->address = NULL; 312*37da2899SCharles.Forsyth node->size = 0; 313*37da2899SCharles.Forsyth 314*37da2899SCharles.Forsyth free( node ); 315*37da2899SCharles.Forsyth node = next; 316*37da2899SCharles.Forsyth } 317*37da2899SCharles.Forsyth table->buckets[i] = 0; 318*37da2899SCharles.Forsyth } 319*37da2899SCharles.Forsyth ft_mem_table_free( table, table->buckets ); 320*37da2899SCharles.Forsyth table->buckets = NULL; 321*37da2899SCharles.Forsyth 322*37da2899SCharles.Forsyth table->size = 0; 323*37da2899SCharles.Forsyth table->nodes = 0; 324*37da2899SCharles.Forsyth 325*37da2899SCharles.Forsyth printf( 326*37da2899SCharles.Forsyth "FreeType: total memory allocations = %ld\n", table->alloc_total ); 327*37da2899SCharles.Forsyth printf( 328*37da2899SCharles.Forsyth "FreeType: maximum memory footprint = %ld\n", table->alloc_max ); 329*37da2899SCharles.Forsyth 330*37da2899SCharles.Forsyth free( table ); 331*37da2899SCharles.Forsyth 332*37da2899SCharles.Forsyth if ( leak_count > 0 ) 333*37da2899SCharles.Forsyth ft_mem_debug_panic( 334*37da2899SCharles.Forsyth "FreeType: %ld bytes of memory leaked in %ld blocks\n", 335*37da2899SCharles.Forsyth leaks, leak_count ); 336*37da2899SCharles.Forsyth printf( "FreeType: No memory leaks detected!\n" ); 337*37da2899SCharles.Forsyth } 338*37da2899SCharles.Forsyth } 339*37da2899SCharles.Forsyth 340*37da2899SCharles.Forsyth 341*37da2899SCharles.Forsyth static FT_MemNode* ft_mem_table_get_nodep(FT_MemTable table,FT_Byte * address)342*37da2899SCharles.Forsyth ft_mem_table_get_nodep( FT_MemTable table, 343*37da2899SCharles.Forsyth FT_Byte* address ) 344*37da2899SCharles.Forsyth { 345*37da2899SCharles.Forsyth FT_ULong hash; 346*37da2899SCharles.Forsyth FT_MemNode *pnode, node; 347*37da2899SCharles.Forsyth 348*37da2899SCharles.Forsyth 349*37da2899SCharles.Forsyth hash = FT_MEM_VAL( address ); 350*37da2899SCharles.Forsyth pnode = table->buckets + ( hash % table->size ); 351*37da2899SCharles.Forsyth 352*37da2899SCharles.Forsyth for (;;) 353*37da2899SCharles.Forsyth { 354*37da2899SCharles.Forsyth node = pnode[0]; 355*37da2899SCharles.Forsyth if ( !node ) 356*37da2899SCharles.Forsyth break; 357*37da2899SCharles.Forsyth 358*37da2899SCharles.Forsyth if ( node->address == address ) 359*37da2899SCharles.Forsyth break; 360*37da2899SCharles.Forsyth 361*37da2899SCharles.Forsyth pnode = &node->link; 362*37da2899SCharles.Forsyth } 363*37da2899SCharles.Forsyth return pnode; 364*37da2899SCharles.Forsyth } 365*37da2899SCharles.Forsyth 366*37da2899SCharles.Forsyth 367*37da2899SCharles.Forsyth static void ft_mem_table_set(FT_MemTable table,FT_Byte * address,FT_ULong size)368*37da2899SCharles.Forsyth ft_mem_table_set( FT_MemTable table, 369*37da2899SCharles.Forsyth FT_Byte* address, 370*37da2899SCharles.Forsyth FT_ULong size ) 371*37da2899SCharles.Forsyth { 372*37da2899SCharles.Forsyth FT_MemNode *pnode, node; 373*37da2899SCharles.Forsyth 374*37da2899SCharles.Forsyth 375*37da2899SCharles.Forsyth if ( table ) 376*37da2899SCharles.Forsyth { 377*37da2899SCharles.Forsyth pnode = ft_mem_table_get_nodep( table, address ); 378*37da2899SCharles.Forsyth node = *pnode; 379*37da2899SCharles.Forsyth if ( node ) 380*37da2899SCharles.Forsyth { 381*37da2899SCharles.Forsyth if ( node->size < 0 ) 382*37da2899SCharles.Forsyth { 383*37da2899SCharles.Forsyth /* this block was already freed. This means that our memory is */ 384*37da2899SCharles.Forsyth /* now completely corrupted! */ 385*37da2899SCharles.Forsyth ft_mem_debug_panic( 386*37da2899SCharles.Forsyth "memory heap corrupted (allocating freed block)" ); 387*37da2899SCharles.Forsyth } 388*37da2899SCharles.Forsyth else 389*37da2899SCharles.Forsyth { 390*37da2899SCharles.Forsyth /* this block was already allocated. This means that our memory */ 391*37da2899SCharles.Forsyth /* is also corrupted! */ 392*37da2899SCharles.Forsyth ft_mem_debug_panic( 393*37da2899SCharles.Forsyth "memory heap corrupted (re-allocating allocated block)" ); 394*37da2899SCharles.Forsyth } 395*37da2899SCharles.Forsyth } 396*37da2899SCharles.Forsyth 397*37da2899SCharles.Forsyth /* we need to create a new node in this table */ 398*37da2899SCharles.Forsyth node = (FT_MemNode)ft_mem_table_alloc( table, sizeof ( *node ) ); 399*37da2899SCharles.Forsyth if ( node == NULL ) 400*37da2899SCharles.Forsyth ft_mem_debug_panic( "not enough memory to run memory tests" ); 401*37da2899SCharles.Forsyth 402*37da2899SCharles.Forsyth node->address = address; 403*37da2899SCharles.Forsyth node->size = size; 404*37da2899SCharles.Forsyth 405*37da2899SCharles.Forsyth node->alloc_file_name = table->file_name; 406*37da2899SCharles.Forsyth node->alloc_line_no = table->line_no; 407*37da2899SCharles.Forsyth 408*37da2899SCharles.Forsyth node->free_file_name = NULL; 409*37da2899SCharles.Forsyth node->free_line_no = 0; 410*37da2899SCharles.Forsyth 411*37da2899SCharles.Forsyth node->link = pnode[0]; 412*37da2899SCharles.Forsyth 413*37da2899SCharles.Forsyth pnode[0] = node; 414*37da2899SCharles.Forsyth table->nodes++; 415*37da2899SCharles.Forsyth 416*37da2899SCharles.Forsyth table->alloc_total += size; 417*37da2899SCharles.Forsyth table->alloc_current += size; 418*37da2899SCharles.Forsyth if ( table->alloc_current > table->alloc_max ) 419*37da2899SCharles.Forsyth table->alloc_max = table->alloc_current; 420*37da2899SCharles.Forsyth 421*37da2899SCharles.Forsyth if ( table->nodes * 3 < table->size || 422*37da2899SCharles.Forsyth table->size * 3 < table->nodes ) 423*37da2899SCharles.Forsyth ft_mem_table_resize( table ); 424*37da2899SCharles.Forsyth } 425*37da2899SCharles.Forsyth } 426*37da2899SCharles.Forsyth 427*37da2899SCharles.Forsyth 428*37da2899SCharles.Forsyth static void ft_mem_table_remove(FT_MemTable table,FT_Byte * address)429*37da2899SCharles.Forsyth ft_mem_table_remove( FT_MemTable table, 430*37da2899SCharles.Forsyth FT_Byte* address ) 431*37da2899SCharles.Forsyth { 432*37da2899SCharles.Forsyth if ( table ) 433*37da2899SCharles.Forsyth { 434*37da2899SCharles.Forsyth FT_MemNode *pnode, node; 435*37da2899SCharles.Forsyth 436*37da2899SCharles.Forsyth 437*37da2899SCharles.Forsyth pnode = ft_mem_table_get_nodep( table, address ); 438*37da2899SCharles.Forsyth node = *pnode; 439*37da2899SCharles.Forsyth if ( node ) 440*37da2899SCharles.Forsyth { 441*37da2899SCharles.Forsyth if ( node->size < 0 ) 442*37da2899SCharles.Forsyth ft_mem_debug_panic( 443*37da2899SCharles.Forsyth "freeing memory block at %p more than once at (%s:%ld)\n" 444*37da2899SCharles.Forsyth "block allocated at (%s:%ld) and released at (%s:%ld)", 445*37da2899SCharles.Forsyth address, 446*37da2899SCharles.Forsyth FT_FILENAME( table->file_name ), table->line_no, 447*37da2899SCharles.Forsyth FT_FILENAME( node->alloc_file_name ), node->alloc_line_no, 448*37da2899SCharles.Forsyth FT_FILENAME( node->free_file_name ), node->free_line_no ); 449*37da2899SCharles.Forsyth 450*37da2899SCharles.Forsyth /* we simply invert the node's size to indicate that the node */ 451*37da2899SCharles.Forsyth /* was freed. We also change its contents. */ 452*37da2899SCharles.Forsyth FT_MEM_SET( address, 0xF3, node->size ); 453*37da2899SCharles.Forsyth 454*37da2899SCharles.Forsyth table->alloc_current -= node->size; 455*37da2899SCharles.Forsyth node->size = -node->size; 456*37da2899SCharles.Forsyth node->free_file_name = table->file_name; 457*37da2899SCharles.Forsyth node->free_line_no = table->line_no; 458*37da2899SCharles.Forsyth } 459*37da2899SCharles.Forsyth else 460*37da2899SCharles.Forsyth ft_mem_debug_panic( 461*37da2899SCharles.Forsyth "trying to free unknown block at %p in (%s:%ld)\n", 462*37da2899SCharles.Forsyth address, 463*37da2899SCharles.Forsyth FT_FILENAME( table->file_name ), table->line_no ); 464*37da2899SCharles.Forsyth } 465*37da2899SCharles.Forsyth } 466*37da2899SCharles.Forsyth 467*37da2899SCharles.Forsyth 468*37da2899SCharles.Forsyth extern FT_Pointer ft_mem_debug_alloc(FT_Memory memory,FT_Long size)469*37da2899SCharles.Forsyth ft_mem_debug_alloc( FT_Memory memory, 470*37da2899SCharles.Forsyth FT_Long size ) 471*37da2899SCharles.Forsyth { 472*37da2899SCharles.Forsyth FT_MemTable table = (FT_MemTable)memory->user; 473*37da2899SCharles.Forsyth FT_Byte* block; 474*37da2899SCharles.Forsyth 475*37da2899SCharles.Forsyth 476*37da2899SCharles.Forsyth if ( size <= 0 ) 477*37da2899SCharles.Forsyth ft_mem_debug_panic( "negative block size allocation (%ld)", size ); 478*37da2899SCharles.Forsyth 479*37da2899SCharles.Forsyth block = (FT_Byte *)ft_mem_table_alloc( table, size ); 480*37da2899SCharles.Forsyth if ( block ) 481*37da2899SCharles.Forsyth ft_mem_table_set( table, block, (FT_ULong)size ); 482*37da2899SCharles.Forsyth 483*37da2899SCharles.Forsyth table->file_name = NULL; 484*37da2899SCharles.Forsyth table->line_no = 0; 485*37da2899SCharles.Forsyth 486*37da2899SCharles.Forsyth return (FT_Pointer) block; 487*37da2899SCharles.Forsyth } 488*37da2899SCharles.Forsyth 489*37da2899SCharles.Forsyth 490*37da2899SCharles.Forsyth extern void ft_mem_debug_free(FT_Memory memory,FT_Pointer block)491*37da2899SCharles.Forsyth ft_mem_debug_free( FT_Memory memory, 492*37da2899SCharles.Forsyth FT_Pointer block ) 493*37da2899SCharles.Forsyth { 494*37da2899SCharles.Forsyth FT_MemTable table = (FT_MemTable)memory->user; 495*37da2899SCharles.Forsyth 496*37da2899SCharles.Forsyth 497*37da2899SCharles.Forsyth if ( block == NULL ) 498*37da2899SCharles.Forsyth ft_mem_debug_panic( "trying to free NULL in (%s:%ld)", 499*37da2899SCharles.Forsyth FT_FILENAME( table->file_name ), 500*37da2899SCharles.Forsyth table->line_no ); 501*37da2899SCharles.Forsyth 502*37da2899SCharles.Forsyth ft_mem_table_remove( table, (FT_Byte*)block ); 503*37da2899SCharles.Forsyth 504*37da2899SCharles.Forsyth /* we never really free the block */ 505*37da2899SCharles.Forsyth table->file_name = NULL; 506*37da2899SCharles.Forsyth table->line_no = 0; 507*37da2899SCharles.Forsyth } 508*37da2899SCharles.Forsyth 509*37da2899SCharles.Forsyth 510*37da2899SCharles.Forsyth extern FT_Pointer ft_mem_debug_realloc(FT_Memory memory,FT_Long cur_size,FT_Long new_size,FT_Pointer block)511*37da2899SCharles.Forsyth ft_mem_debug_realloc( FT_Memory memory, 512*37da2899SCharles.Forsyth FT_Long cur_size, 513*37da2899SCharles.Forsyth FT_Long new_size, 514*37da2899SCharles.Forsyth FT_Pointer block ) 515*37da2899SCharles.Forsyth { 516*37da2899SCharles.Forsyth FT_MemTable table = (FT_MemTable)memory->user; 517*37da2899SCharles.Forsyth FT_MemNode node, *pnode; 518*37da2899SCharles.Forsyth FT_Pointer new_block; 519*37da2899SCharles.Forsyth 520*37da2899SCharles.Forsyth const char* file_name = FT_FILENAME( table->file_name ); 521*37da2899SCharles.Forsyth FT_Long line_no = table->line_no; 522*37da2899SCharles.Forsyth 523*37da2899SCharles.Forsyth 524*37da2899SCharles.Forsyth if ( block == NULL || cur_size == 0 ) 525*37da2899SCharles.Forsyth ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)", 526*37da2899SCharles.Forsyth file_name, line_no ); 527*37da2899SCharles.Forsyth 528*37da2899SCharles.Forsyth if ( new_size <= 0 ) 529*37da2899SCharles.Forsyth ft_mem_debug_panic( 530*37da2899SCharles.Forsyth "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)", 531*37da2899SCharles.Forsyth block, cur_size, file_name, line_no ); 532*37da2899SCharles.Forsyth 533*37da2899SCharles.Forsyth /* check 'cur_size' value */ 534*37da2899SCharles.Forsyth pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block ); 535*37da2899SCharles.Forsyth node = *pnode; 536*37da2899SCharles.Forsyth if ( !node ) 537*37da2899SCharles.Forsyth ft_mem_debug_panic( 538*37da2899SCharles.Forsyth "trying to reallocate unknown block at %p in (%s:%ld)", 539*37da2899SCharles.Forsyth block, file_name, line_no ); 540*37da2899SCharles.Forsyth 541*37da2899SCharles.Forsyth if ( node->size <= 0 ) 542*37da2899SCharles.Forsyth ft_mem_debug_panic( 543*37da2899SCharles.Forsyth "trying to reallocate freed block at %p in (%s:%ld)", 544*37da2899SCharles.Forsyth block, file_name, line_no ); 545*37da2899SCharles.Forsyth 546*37da2899SCharles.Forsyth if ( node->size != cur_size ) 547*37da2899SCharles.Forsyth ft_mem_debug_panic( "invalid ft_realloc request for %p. cur_size is " 548*37da2899SCharles.Forsyth "%ld instead of %ld in (%s:%ld)", 549*37da2899SCharles.Forsyth block, cur_size, node->size, file_name, line_no ); 550*37da2899SCharles.Forsyth 551*37da2899SCharles.Forsyth new_block = ft_mem_debug_alloc( memory, new_size ); 552*37da2899SCharles.Forsyth if ( new_block == NULL ) 553*37da2899SCharles.Forsyth return NULL; 554*37da2899SCharles.Forsyth 555*37da2899SCharles.Forsyth ft_memcpy( new_block, block, cur_size < new_size ? cur_size : new_size ); 556*37da2899SCharles.Forsyth 557*37da2899SCharles.Forsyth table->file_name = file_name; 558*37da2899SCharles.Forsyth table->line_no = line_no; 559*37da2899SCharles.Forsyth 560*37da2899SCharles.Forsyth ft_mem_debug_free( memory, (FT_Byte*)block ); 561*37da2899SCharles.Forsyth 562*37da2899SCharles.Forsyth return new_block; 563*37da2899SCharles.Forsyth } 564*37da2899SCharles.Forsyth 565*37da2899SCharles.Forsyth 566*37da2899SCharles.Forsyth extern FT_Int ft_mem_debug_init(FT_Memory memory)567*37da2899SCharles.Forsyth ft_mem_debug_init( FT_Memory memory ) 568*37da2899SCharles.Forsyth { 569*37da2899SCharles.Forsyth FT_MemTable table; 570*37da2899SCharles.Forsyth FT_Int result = 0; 571*37da2899SCharles.Forsyth 572*37da2899SCharles.Forsyth 573*37da2899SCharles.Forsyth if ( getenv( "FT_DEBUG_MEMORY" ) ) 574*37da2899SCharles.Forsyth { 575*37da2899SCharles.Forsyth table = ft_mem_table_new( memory ); 576*37da2899SCharles.Forsyth if ( table ) 577*37da2899SCharles.Forsyth { 578*37da2899SCharles.Forsyth memory->user = table; 579*37da2899SCharles.Forsyth memory->alloc = ft_mem_debug_alloc; 580*37da2899SCharles.Forsyth memory->realloc = ft_mem_debug_realloc; 581*37da2899SCharles.Forsyth memory->free = ft_mem_debug_free; 582*37da2899SCharles.Forsyth result = 1; 583*37da2899SCharles.Forsyth } 584*37da2899SCharles.Forsyth } 585*37da2899SCharles.Forsyth return result; 586*37da2899SCharles.Forsyth } 587*37da2899SCharles.Forsyth 588*37da2899SCharles.Forsyth 589*37da2899SCharles.Forsyth extern void ft_mem_debug_done(FT_Memory memory)590*37da2899SCharles.Forsyth ft_mem_debug_done( FT_Memory memory ) 591*37da2899SCharles.Forsyth { 592*37da2899SCharles.Forsyth FT_MemTable table = (FT_MemTable)memory->user; 593*37da2899SCharles.Forsyth 594*37da2899SCharles.Forsyth 595*37da2899SCharles.Forsyth if ( table ) 596*37da2899SCharles.Forsyth { 597*37da2899SCharles.Forsyth memory->free = table->free; 598*37da2899SCharles.Forsyth memory->realloc = table->realloc; 599*37da2899SCharles.Forsyth memory->alloc = table->alloc; 600*37da2899SCharles.Forsyth 601*37da2899SCharles.Forsyth ft_mem_table_destroy( table ); 602*37da2899SCharles.Forsyth memory->user = NULL; 603*37da2899SCharles.Forsyth } 604*37da2899SCharles.Forsyth } 605*37da2899SCharles.Forsyth 606*37da2899SCharles.Forsyth 607*37da2899SCharles.Forsyth FT_BASE_DEF( FT_Error ) FT_Alloc_Debug(FT_Memory memory,FT_Long size,void ** P,const char * file_name,FT_Long line_no)608*37da2899SCharles.Forsyth FT_Alloc_Debug( FT_Memory memory, 609*37da2899SCharles.Forsyth FT_Long size, 610*37da2899SCharles.Forsyth void* *P, 611*37da2899SCharles.Forsyth const char* file_name, 612*37da2899SCharles.Forsyth FT_Long line_no ) 613*37da2899SCharles.Forsyth { 614*37da2899SCharles.Forsyth FT_MemTable table = (FT_MemTable)memory->user; 615*37da2899SCharles.Forsyth 616*37da2899SCharles.Forsyth 617*37da2899SCharles.Forsyth if ( table ) 618*37da2899SCharles.Forsyth { 619*37da2899SCharles.Forsyth table->file_name = file_name; 620*37da2899SCharles.Forsyth table->line_no = line_no; 621*37da2899SCharles.Forsyth } 622*37da2899SCharles.Forsyth return FT_Alloc( memory, size, P ); 623*37da2899SCharles.Forsyth } 624*37da2899SCharles.Forsyth 625*37da2899SCharles.Forsyth 626*37da2899SCharles.Forsyth FT_BASE_DEF( FT_Error ) FT_Realloc_Debug(FT_Memory memory,FT_Long current,FT_Long size,void ** P,const char * file_name,FT_Long line_no)627*37da2899SCharles.Forsyth FT_Realloc_Debug( FT_Memory memory, 628*37da2899SCharles.Forsyth FT_Long current, 629*37da2899SCharles.Forsyth FT_Long size, 630*37da2899SCharles.Forsyth void* *P, 631*37da2899SCharles.Forsyth const char* file_name, 632*37da2899SCharles.Forsyth FT_Long line_no ) 633*37da2899SCharles.Forsyth { 634*37da2899SCharles.Forsyth FT_MemTable table = (FT_MemTable)memory->user; 635*37da2899SCharles.Forsyth 636*37da2899SCharles.Forsyth 637*37da2899SCharles.Forsyth if ( table ) 638*37da2899SCharles.Forsyth { 639*37da2899SCharles.Forsyth table->file_name = file_name; 640*37da2899SCharles.Forsyth table->line_no = line_no; 641*37da2899SCharles.Forsyth } 642*37da2899SCharles.Forsyth return FT_Realloc( memory, current, size, P ); 643*37da2899SCharles.Forsyth } 644*37da2899SCharles.Forsyth 645*37da2899SCharles.Forsyth 646*37da2899SCharles.Forsyth FT_BASE_DEF( void ) FT_Free_Debug(FT_Memory memory,FT_Pointer block,const char * file_name,FT_Long line_no)647*37da2899SCharles.Forsyth FT_Free_Debug( FT_Memory memory, 648*37da2899SCharles.Forsyth FT_Pointer block, 649*37da2899SCharles.Forsyth const char* file_name, 650*37da2899SCharles.Forsyth FT_Long line_no ) 651*37da2899SCharles.Forsyth { 652*37da2899SCharles.Forsyth FT_MemTable table = (FT_MemTable)memory->user; 653*37da2899SCharles.Forsyth 654*37da2899SCharles.Forsyth 655*37da2899SCharles.Forsyth if ( table ) 656*37da2899SCharles.Forsyth { 657*37da2899SCharles.Forsyth table->file_name = file_name; 658*37da2899SCharles.Forsyth table->line_no = line_no; 659*37da2899SCharles.Forsyth } 660*37da2899SCharles.Forsyth FT_Free( memory, (void **)block ); 661*37da2899SCharles.Forsyth } 662*37da2899SCharles.Forsyth 663*37da2899SCharles.Forsyth 664*37da2899SCharles.Forsyth #else /* !FT_DEBUG_MEMORY */ 665*37da2899SCharles.Forsyth 666*37da2899SCharles.Forsyth /* ANSI C doesn't like empty source files */ 667*37da2899SCharles.Forsyth const FT_Byte _debug_mem_dummy = 0; 668*37da2899SCharles.Forsyth 669*37da2899SCharles.Forsyth #endif /* !FT_DEBUG_MEMORY */ 670*37da2899SCharles.Forsyth 671*37da2899SCharles.Forsyth 672*37da2899SCharles.Forsyth /* END */ 673