ftdbgmem.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  ftdbgmem.c                                                             */
00004 /*                                                                         */
00005 /*    Memory debugger (body).                                              */
00006 /*                                                                         */
00007 /*  Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2009 by                  */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018 
00019 #include <ft2build.h>
00020 #include FT_CONFIG_CONFIG_H
00021 #include FT_INTERNAL_DEBUG_H
00022 #include FT_INTERNAL_MEMORY_H
00023 #include FT_SYSTEM_H
00024 #include FT_ERRORS_H
00025 #include FT_TYPES_H
00026 
00027 
00028 #ifdef FT_DEBUG_MEMORY
00029 
00030 #define  KEEPALIVE /* `Keep alive' means that freed blocks aren't released
00031                     * to the heap.  This is useful to detect double-frees
00032                     * or weird heap corruption, but it uses large amounts of
00033                     * memory, however.
00034                     */
00035 
00036 #include FT_CONFIG_STANDARD_LIBRARY_H
00037 
00038   FT_BASE_DEF( const char* )  _ft_debug_file   = 0;
00039   FT_BASE_DEF( long )         _ft_debug_lineno = 0;
00040 
00041   extern void
00042   FT_DumpMemory( FT_Memory  memory );
00043 
00044 
00045   typedef struct FT_MemSourceRec_*  FT_MemSource;
00046   typedef struct FT_MemNodeRec_*    FT_MemNode;
00047   typedef struct FT_MemTableRec_*   FT_MemTable;
00048 
00049 
00050 #define FT_MEM_VAL( addr )  ((FT_ULong)(FT_Pointer)( addr ))
00051 
00052   /*
00053    *  This structure holds statistics for a single allocation/release
00054    *  site.  This is useful to know where memory operations happen the
00055    *  most.
00056    */
00057   typedef struct  FT_MemSourceRec_
00058   {
00059     const char*   file_name;
00060     long          line_no;
00061 
00062     FT_Long       cur_blocks;   /* current number of allocated blocks */
00063     FT_Long       max_blocks;   /* max. number of allocated blocks    */
00064     FT_Long       all_blocks;   /* total number of blocks allocated   */
00065 
00066     FT_Long       cur_size;     /* current cumulative allocated size */
00067     FT_Long       max_size;     /* maximum cumulative allocated size */
00068     FT_Long       all_size;     /* total cumulative allocated size   */
00069 
00070     FT_Long       cur_max;      /* current maximum allocated size */
00071 
00072     FT_UInt32     hash;
00073     FT_MemSource  link;
00074 
00075   } FT_MemSourceRec;
00076 
00077 
00078   /*
00079    *  We don't need a resizable array for the memory sources, because
00080    *  their number is pretty limited within FreeType.
00081    */
00082 #define FT_MEM_SOURCE_BUCKETS  128
00083 
00084   /*
00085    *  This structure holds information related to a single allocated
00086    *  memory block.  If KEEPALIVE is defined, blocks that are freed by
00087    *  FreeType are never released to the system.  Instead, their `size'
00088    *  field is set to -size.  This is mainly useful to detect double frees,
00089    *  at the price of large memory footprint during execution.
00090    */
00091   typedef struct  FT_MemNodeRec_
00092   {
00093     FT_Byte*      address;
00094     FT_Long       size;     /* < 0 if the block was freed */
00095 
00096     FT_MemSource  source;
00097 
00098 #ifdef KEEPALIVE
00099     const char*   free_file_name;
00100     FT_Long       free_line_no;
00101 #endif
00102 
00103     FT_MemNode    link;
00104 
00105   } FT_MemNodeRec;
00106 
00107 
00108   /*
00109    *  The global structure, containing compound statistics and all hash
00110    *  tables.
00111    */
00112   typedef struct  FT_MemTableRec_
00113   {
00114     FT_ULong         size;
00115     FT_ULong         nodes;
00116     FT_MemNode*      buckets;
00117 
00118     FT_ULong         alloc_total;
00119     FT_ULong         alloc_current;
00120     FT_ULong         alloc_max;
00121     FT_ULong         alloc_count;
00122 
00123     FT_Bool          bound_total;
00124     FT_ULong         alloc_total_max;
00125 
00126     FT_Bool          bound_count;
00127     FT_ULong         alloc_count_max;
00128 
00129     FT_MemSource     sources[FT_MEM_SOURCE_BUCKETS];
00130 
00131     FT_Bool          keep_alive;
00132 
00133     FT_Memory        memory;
00134     FT_Pointer       memory_user;
00135     FT_Alloc_Func    alloc;
00136     FT_Free_Func     free;
00137     FT_Realloc_Func  realloc;
00138 
00139   } FT_MemTableRec;
00140 
00141 
00142 #define FT_MEM_SIZE_MIN  7
00143 #define FT_MEM_SIZE_MAX  13845163
00144 
00145 #define FT_FILENAME( x )  ((x) ? (x) : "unknown file")
00146 
00147 
00148   /*
00149    *  Prime numbers are ugly to handle.  It would be better to implement
00150    *  L-Hashing, which is 10% faster and doesn't require divisions.
00151    */
00152   static const FT_UInt  ft_mem_primes[] =
00153   {
00154     7,
00155     11,
00156     19,
00157     37,
00158     73,
00159     109,
00160     163,
00161     251,
00162     367,
00163     557,
00164     823,
00165     1237,
00166     1861,
00167     2777,
00168     4177,
00169     6247,
00170     9371,
00171     14057,
00172     21089,
00173     31627,
00174     47431,
00175     71143,
00176     106721,
00177     160073,
00178     240101,
00179     360163,
00180     540217,
00181     810343,
00182     1215497,
00183     1823231,
00184     2734867,
00185     4102283,
00186     6153409,
00187     9230113,
00188     13845163,
00189   };
00190 
00191 
00192   static FT_ULong
00193   ft_mem_closest_prime( FT_ULong  num )
00194   {
00195     FT_UInt  i;
00196 
00197 
00198     for ( i = 0;
00199           i < sizeof ( ft_mem_primes ) / sizeof ( ft_mem_primes[0] ); i++ )
00200       if ( ft_mem_primes[i] > num )
00201         return ft_mem_primes[i];
00202 
00203     return FT_MEM_SIZE_MAX;
00204   }
00205 
00206 
00207   extern void
00208   ft_mem_debug_panic( const char*  fmt,
00209                       ... )
00210   {
00211     va_list  ap;
00212 
00213 
00214     printf( "FreeType.Debug: " );
00215 
00216     va_start( ap, fmt );
00217     vprintf( fmt, ap );
00218     va_end( ap );
00219 
00220     printf( "\n" );
00221     exit( EXIT_FAILURE );
00222   }
00223 
00224 
00225   static FT_Pointer
00226   ft_mem_table_alloc( FT_MemTable  table,
00227                       FT_Long      size )
00228   {
00229     FT_Memory   memory = table->memory;
00230     FT_Pointer  block;
00231 
00232 
00233     memory->user = table->memory_user;
00234     block = table->alloc( memory, size );
00235     memory->user = table;
00236 
00237     return block;
00238   }
00239 
00240 
00241   static void
00242   ft_mem_table_free( FT_MemTable  table,
00243                      FT_Pointer   block )
00244   {
00245     FT_Memory  memory = table->memory;
00246 
00247 
00248     memory->user = table->memory_user;
00249     table->free( memory, block );
00250     memory->user = table;
00251   }
00252 
00253 
00254   static void
00255   ft_mem_table_resize( FT_MemTable  table )
00256   {
00257     FT_ULong  new_size;
00258 
00259 
00260     new_size = ft_mem_closest_prime( table->nodes );
00261     if ( new_size != table->size )
00262     {
00263       FT_MemNode*  new_buckets;
00264       FT_ULong     i;
00265 
00266 
00267       new_buckets = (FT_MemNode *)
00268                       ft_mem_table_alloc( table,
00269                                           new_size * sizeof ( FT_MemNode ) );
00270       if ( new_buckets == NULL )
00271         return;
00272 
00273       FT_ARRAY_ZERO( new_buckets, new_size );
00274 
00275       for ( i = 0; i < table->size; i++ )
00276       {
00277         FT_MemNode  node, next, *pnode;
00278         FT_ULong    hash;
00279 
00280 
00281         node = table->buckets[i];
00282         while ( node )
00283         {
00284           next  = node->link;
00285           hash  = FT_MEM_VAL( node->address ) % new_size;
00286           pnode = new_buckets + hash;
00287 
00288           node->link = pnode[0];
00289           pnode[0]   = node;
00290 
00291           node = next;
00292         }
00293       }
00294 
00295       if ( table->buckets )
00296         ft_mem_table_free( table, table->buckets );
00297 
00298       table->buckets = new_buckets;
00299       table->size    = new_size;
00300     }
00301   }
00302 
00303 
00304   static FT_MemTable
00305   ft_mem_table_new( FT_Memory  memory )
00306   {
00307     FT_MemTable  table;
00308 
00309 
00310     table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) );
00311     if ( table == NULL )
00312       goto Exit;
00313 
00314     FT_ZERO( table );
00315 
00316     table->size  = FT_MEM_SIZE_MIN;
00317     table->nodes = 0;
00318 
00319     table->memory = memory;
00320 
00321     table->memory_user = memory->user;
00322 
00323     table->alloc   = memory->alloc;
00324     table->realloc = memory->realloc;
00325     table->free    = memory->free;
00326 
00327     table->buckets = (FT_MemNode *)
00328                        memory->alloc( memory,
00329                                       table->size * sizeof ( FT_MemNode ) );
00330     if ( table->buckets )
00331       FT_ARRAY_ZERO( table->buckets, table->size );
00332     else
00333     {
00334       memory->free( memory, table );
00335       table = NULL;
00336     }
00337 
00338   Exit:
00339     return table;
00340   }
00341 
00342 
00343   static void
00344   ft_mem_table_destroy( FT_MemTable  table )
00345   {
00346     FT_ULong  i;
00347 
00348 
00349     FT_DumpMemory( table->memory );
00350 
00351     if ( table )
00352     {
00353       FT_Long   leak_count = 0;
00354       FT_ULong  leaks      = 0;
00355 
00356 
00357       /* remove all blocks from the table, revealing leaked ones */
00358       for ( i = 0; i < table->size; i++ )
00359       {
00360         FT_MemNode  *pnode = table->buckets + i, next, node = *pnode;
00361 
00362 
00363         while ( node )
00364         {
00365           next       = node->link;
00366           node->link = 0;
00367 
00368           if ( node->size > 0 )
00369           {
00370             printf(
00371               "leaked memory block at address %p, size %8ld in (%s:%ld)\n",
00372               node->address, node->size,
00373               FT_FILENAME( node->source->file_name ),
00374               node->source->line_no );
00375 
00376             leak_count++;
00377             leaks += node->size;
00378 
00379             ft_mem_table_free( table, node->address );
00380           }
00381 
00382           node->address = NULL;
00383           node->size    = 0;
00384 
00385           ft_mem_table_free( table, node );
00386           node = next;
00387         }
00388         table->buckets[i] = 0;
00389       }
00390 
00391       ft_mem_table_free( table, table->buckets );
00392       table->buckets = NULL;
00393 
00394       table->size  = 0;
00395       table->nodes = 0;
00396 
00397       /* remove all sources */
00398       for ( i = 0; i < FT_MEM_SOURCE_BUCKETS; i++ )
00399       {
00400         FT_MemSource  source, next;
00401 
00402 
00403         for ( source = table->sources[i]; source != NULL; source = next )
00404         {
00405           next = source->link;
00406           ft_mem_table_free( table, source );
00407         }
00408 
00409         table->sources[i] = NULL;
00410       }
00411 
00412       printf(
00413         "FreeType: total memory allocations = %ld\n", table->alloc_total );
00414       printf(
00415         "FreeType: maximum memory footprint = %ld\n", table->alloc_max );
00416 
00417       ft_mem_table_free( table, table );
00418 
00419       if ( leak_count > 0 )
00420         ft_mem_debug_panic(
00421           "FreeType: %ld bytes of memory leaked in %ld blocks\n",
00422           leaks, leak_count );
00423 
00424       printf( "FreeType: no memory leaks detected\n" );
00425     }
00426   }
00427 
00428 
00429   static FT_MemNode*
00430   ft_mem_table_get_nodep( FT_MemTable  table,
00431                           FT_Byte*     address )
00432   {
00433     FT_ULong     hash;
00434     FT_MemNode  *pnode, node;
00435 
00436 
00437     hash  = FT_MEM_VAL( address );
00438     pnode = table->buckets + ( hash % table->size );
00439 
00440     for (;;)
00441     {
00442       node = pnode[0];
00443       if ( !node )
00444         break;
00445 
00446       if ( node->address == address )
00447         break;
00448 
00449       pnode = &node->link;
00450     }
00451     return pnode;
00452   }
00453 
00454 
00455   static FT_MemSource
00456   ft_mem_table_get_source( FT_MemTable  table )
00457   {
00458     FT_UInt32     hash;
00459     FT_MemSource  node, *pnode;
00460 
00461 
00462     /* cast to FT_PtrDist first since void* can be larger */
00463     /* than FT_UInt32 and GCC 4.1.1 emits a warning       */
00464     hash  = (FT_UInt32)(FT_PtrDist)(void*)_ft_debug_file +
00465               (FT_UInt32)( 5 * _ft_debug_lineno );
00466     pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS];
00467 
00468     for ( ;; )
00469     {
00470       node = *pnode;
00471       if ( node == NULL )
00472         break;
00473 
00474       if ( node->file_name == _ft_debug_file &&
00475            node->line_no   == _ft_debug_lineno   )
00476         goto Exit;
00477 
00478       pnode = &node->link;
00479     }
00480 
00481     node = (FT_MemSource)ft_mem_table_alloc( table, sizeof ( *node ) );
00482     if ( node == NULL )
00483       ft_mem_debug_panic(
00484         "not enough memory to perform memory debugging\n" );
00485 
00486     node->file_name = _ft_debug_file;
00487     node->line_no   = _ft_debug_lineno;
00488 
00489     node->cur_blocks = 0;
00490     node->max_blocks = 0;
00491     node->all_blocks = 0;
00492 
00493     node->cur_size   = 0;
00494     node->max_size   = 0;
00495     node->all_size   = 0;
00496 
00497     node->cur_max    = 0;
00498 
00499     node->link = NULL;
00500     node->hash = hash;
00501     *pnode     = node;
00502 
00503   Exit:
00504     return node;
00505   }
00506 
00507 
00508   static void
00509   ft_mem_table_set( FT_MemTable  table,
00510                     FT_Byte*     address,
00511                     FT_ULong     size,
00512                     FT_Long      delta )
00513   {
00514     FT_MemNode  *pnode, node;
00515 
00516 
00517     if ( table )
00518     {
00519       FT_MemSource  source;
00520 
00521 
00522       pnode = ft_mem_table_get_nodep( table, address );
00523       node  = *pnode;
00524       if ( node )
00525       {
00526         if ( node->size < 0 )
00527         {
00528           /* This block was already freed.  Our memory is now completely */
00529           /* corrupted!                                                  */
00530           /* This can only happen in keep-alive mode.                    */
00531           ft_mem_debug_panic(
00532             "memory heap corrupted (allocating freed block)" );
00533         }
00534         else
00535         {
00536           /* This block was already allocated.  This means that our memory */
00537           /* is also corrupted!                                            */
00538           ft_mem_debug_panic(
00539             "memory heap corrupted (re-allocating allocated block at"
00540             " %p, of size %ld)\n"
00541             "org=%s:%d new=%s:%d\n",
00542             node->address, node->size,
00543             FT_FILENAME( node->source->file_name ), node->source->line_no,
00544             FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
00545         }
00546       }
00547 
00548       /* we need to create a new node in this table */
00549       node = (FT_MemNode)ft_mem_table_alloc( table, sizeof ( *node ) );
00550       if ( node == NULL )
00551         ft_mem_debug_panic( "not enough memory to run memory tests" );
00552 
00553       node->address = address;
00554       node->size    = size;
00555       node->source  = source = ft_mem_table_get_source( table );
00556 
00557       if ( delta == 0 )
00558       {
00559         /* this is an allocation */
00560         source->all_blocks++;
00561         source->cur_blocks++;
00562         if ( source->cur_blocks > source->max_blocks )
00563           source->max_blocks = source->cur_blocks;
00564       }
00565 
00566       if ( size > (FT_ULong)source->cur_max )
00567         source->cur_max = size;
00568 
00569       if ( delta != 0 )
00570       {
00571         /* we are growing or shrinking a reallocated block */
00572         source->cur_size     += delta;
00573         table->alloc_current += delta;
00574       }
00575       else
00576       {
00577         /* we are allocating a new block */
00578         source->cur_size     += size;
00579         table->alloc_current += size;
00580       }
00581 
00582       source->all_size += size;
00583 
00584       if ( source->cur_size > source->max_size )
00585         source->max_size = source->cur_size;
00586 
00587       node->free_file_name = NULL;
00588       node->free_line_no   = 0;
00589 
00590       node->link = pnode[0];
00591 
00592       pnode[0] = node;
00593       table->nodes++;
00594 
00595       table->alloc_total += size;
00596 
00597       if ( table->alloc_current > table->alloc_max )
00598         table->alloc_max = table->alloc_current;
00599 
00600       if ( table->nodes * 3 < table->size  ||
00601            table->size  * 3 < table->nodes )
00602         ft_mem_table_resize( table );
00603     }
00604   }
00605 
00606 
00607   static void
00608   ft_mem_table_remove( FT_MemTable  table,
00609                        FT_Byte*     address,
00610                        FT_Long      delta )
00611   {
00612     if ( table )
00613     {
00614       FT_MemNode  *pnode, node;
00615 
00616 
00617       pnode = ft_mem_table_get_nodep( table, address );
00618       node  = *pnode;
00619       if ( node )
00620       {
00621         FT_MemSource  source;
00622 
00623 
00624         if ( node->size < 0 )
00625           ft_mem_debug_panic(
00626             "freeing memory block at %p more than once at (%s:%ld)\n"
00627             "block allocated at (%s:%ld) and released at (%s:%ld)",
00628             address,
00629             FT_FILENAME( _ft_debug_file ), _ft_debug_lineno,
00630             FT_FILENAME( node->source->file_name ), node->source->line_no,
00631             FT_FILENAME( node->free_file_name ), node->free_line_no );
00632 
00633         /* scramble the node's content for additional safety */
00634         FT_MEM_SET( address, 0xF3, node->size );
00635 
00636         if ( delta == 0 )
00637         {
00638           source = node->source;
00639 
00640           source->cur_blocks--;
00641           source->cur_size -= node->size;
00642 
00643           table->alloc_current -= node->size;
00644         }
00645 
00646         if ( table->keep_alive )
00647         {
00648           /* we simply invert the node's size to indicate that the node */
00649           /* was freed.                                                 */
00650           node->size           = -node->size;
00651           node->free_file_name = _ft_debug_file;
00652           node->free_line_no   = _ft_debug_lineno;
00653         }
00654         else
00655         {
00656           table->nodes--;
00657 
00658           *pnode = node->link;
00659 
00660           node->size   = 0;
00661           node->source = NULL;
00662 
00663           ft_mem_table_free( table, node );
00664 
00665           if ( table->nodes * 3 < table->size  ||
00666                table->size  * 3 < table->nodes )
00667             ft_mem_table_resize( table );
00668         }
00669       }
00670       else
00671         ft_mem_debug_panic(
00672           "trying to free unknown block at %p in (%s:%ld)\n",
00673           address,
00674           FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
00675     }
00676   }
00677 
00678 
00679   extern FT_Pointer
00680   ft_mem_debug_alloc( FT_Memory  memory,
00681                       FT_Long    size )
00682   {
00683     FT_MemTable  table = (FT_MemTable)memory->user;
00684     FT_Byte*     block;
00685 
00686 
00687     if ( size <= 0 )
00688       ft_mem_debug_panic( "negative block size allocation (%ld)", size );
00689 
00690     /* return NULL if the maximum number of allocations was reached */
00691     if ( table->bound_count                           &&
00692          table->alloc_count >= table->alloc_count_max )
00693       return NULL;
00694 
00695     /* return NULL if this allocation would overflow the maximum heap size */
00696     if ( table->bound_total                                             &&
00697          table->alloc_total_max - table->alloc_current > (FT_ULong)size )
00698       return NULL;
00699 
00700     block = (FT_Byte *)ft_mem_table_alloc( table, size );
00701     if ( block )
00702     {
00703       ft_mem_table_set( table, block, (FT_ULong)size, 0 );
00704 
00705       table->alloc_count++;
00706     }
00707 
00708     _ft_debug_file   = "<unknown>";
00709     _ft_debug_lineno = 0;
00710 
00711     return (FT_Pointer)block;
00712   }
00713 
00714 
00715   extern void
00716   ft_mem_debug_free( FT_Memory   memory,
00717                      FT_Pointer  block )
00718   {
00719     FT_MemTable  table = (FT_MemTable)memory->user;
00720 
00721 
00722     if ( block == NULL )
00723       ft_mem_debug_panic( "trying to free NULL in (%s:%ld)",
00724                           FT_FILENAME( _ft_debug_file ),
00725                           _ft_debug_lineno );
00726 
00727     ft_mem_table_remove( table, (FT_Byte*)block, 0 );
00728 
00729     if ( !table->keep_alive )
00730       ft_mem_table_free( table, block );
00731 
00732     table->alloc_count--;
00733 
00734     _ft_debug_file   = "<unknown>";
00735     _ft_debug_lineno = 0;
00736   }
00737 
00738 
00739   extern FT_Pointer
00740   ft_mem_debug_realloc( FT_Memory   memory,
00741                         FT_Long     cur_size,
00742                         FT_Long     new_size,
00743                         FT_Pointer  block )
00744   {
00745     FT_MemTable  table = (FT_MemTable)memory->user;
00746     FT_MemNode   node, *pnode;
00747     FT_Pointer   new_block;
00748     FT_Long      delta;
00749 
00750     const char*  file_name = FT_FILENAME( _ft_debug_file );
00751     FT_Long      line_no   = _ft_debug_lineno;
00752 
00753 
00754     /* unlikely, but possible */
00755     if ( new_size == cur_size )
00756       return block;
00757 
00758     /* the following is valid according to ANSI C */
00759 #if 0
00760     if ( block == NULL || cur_size == 0 )
00761       ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)",
00762                           file_name, line_no );
00763 #endif
00764 
00765     /* while the following is allowed in ANSI C also, we abort since */
00766     /* such case should be handled by FreeType.                      */
00767     if ( new_size <= 0 )
00768       ft_mem_debug_panic(
00769         "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)",
00770         block, cur_size, file_name, line_no );
00771 
00772     /* check `cur_size' value */
00773     pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block );
00774     node  = *pnode;
00775     if ( !node )
00776       ft_mem_debug_panic(
00777         "trying to reallocate unknown block at %p in (%s:%ld)",
00778         block, file_name, line_no );
00779 
00780     if ( node->size <= 0 )
00781       ft_mem_debug_panic(
00782         "trying to reallocate freed block at %p in (%s:%ld)",
00783         block, file_name, line_no );
00784 
00785     if ( node->size != cur_size )
00786       ft_mem_debug_panic( "invalid ft_realloc request for %p. cur_size is "
00787                           "%ld instead of %ld in (%s:%ld)",
00788                           block, cur_size, node->size, file_name, line_no );
00789 
00790     /* return NULL if the maximum number of allocations was reached */
00791     if ( table->bound_count                           &&
00792          table->alloc_count >= table->alloc_count_max )
00793       return NULL;
00794 
00795     delta = (FT_Long)( new_size - cur_size );
00796 
00797     /* return NULL if this allocation would overflow the maximum heap size */
00798     if ( delta > 0                                                       &&
00799          table->bound_total                                              &&
00800          table->alloc_current + (FT_ULong)delta > table->alloc_total_max )
00801       return NULL;
00802 
00803     new_block = (FT_Byte *)ft_mem_table_alloc( table, new_size );
00804     if ( new_block == NULL )
00805       return NULL;
00806 
00807     ft_mem_table_set( table, (FT_Byte*)new_block, new_size, delta );
00808 
00809     ft_memcpy( new_block, block, cur_size < new_size ? cur_size : new_size );
00810 
00811     ft_mem_table_remove( table, (FT_Byte*)block, delta );
00812 
00813     _ft_debug_file   = "<unknown>";
00814     _ft_debug_lineno = 0;
00815 
00816     if ( !table->keep_alive )
00817       ft_mem_table_free( table, block );
00818 
00819     return new_block;
00820   }
00821 
00822 
00823   extern FT_Int
00824   ft_mem_debug_init( FT_Memory  memory )
00825   {
00826     FT_MemTable  table;
00827     FT_Int       result = 0;
00828 
00829 
00830     if ( getenv( "FT2_DEBUG_MEMORY" ) )
00831     {
00832       table = ft_mem_table_new( memory );
00833       if ( table )
00834       {
00835         const char*  p;
00836 
00837 
00838         memory->user    = table;
00839         memory->alloc   = ft_mem_debug_alloc;
00840         memory->realloc = ft_mem_debug_realloc;
00841         memory->free    = ft_mem_debug_free;
00842 
00843         p = getenv( "FT2_ALLOC_TOTAL_MAX" );
00844         if ( p != NULL )
00845         {
00846           FT_Long   total_max = ft_atol( p );
00847 
00848 
00849           if ( total_max > 0 )
00850           {
00851             table->bound_total     = 1;
00852             table->alloc_total_max = (FT_ULong)total_max;
00853           }
00854         }
00855 
00856         p = getenv( "FT2_ALLOC_COUNT_MAX" );
00857         if ( p != NULL )
00858         {
00859           FT_Long  total_count = ft_atol( p );
00860 
00861 
00862           if ( total_count > 0 )
00863           {
00864             table->bound_count     = 1;
00865             table->alloc_count_max = (FT_ULong)total_count;
00866           }
00867         }
00868 
00869         p = getenv( "FT2_KEEP_ALIVE" );
00870         if ( p != NULL )
00871         {
00872           FT_Long  keep_alive = ft_atol( p );
00873 
00874 
00875           if ( keep_alive > 0 )
00876             table->keep_alive = 1;
00877         }
00878 
00879         result = 1;
00880       }
00881     }
00882     return result;
00883   }
00884 
00885 
00886   extern void
00887   ft_mem_debug_done( FT_Memory  memory )
00888   {
00889     FT_MemTable  table = (FT_MemTable)memory->user;
00890 
00891 
00892     if ( table )
00893     {
00894       memory->free    = table->free;
00895       memory->realloc = table->realloc;
00896       memory->alloc   = table->alloc;
00897 
00898       ft_mem_table_destroy( table );
00899       memory->user = NULL;
00900     }
00901   }
00902 
00903 
00904 
00905   static int
00906   ft_mem_source_compare( const void*  p1,
00907                          const void*  p2 )
00908   {
00909     FT_MemSource  s1 = *(FT_MemSource*)p1;
00910     FT_MemSource  s2 = *(FT_MemSource*)p2;
00911 
00912 
00913     if ( s2->max_size > s1->max_size )
00914       return 1;
00915     else if ( s2->max_size < s1->max_size )
00916       return -1;
00917     else
00918       return 0;
00919   }
00920 
00921 
00922   extern void
00923   FT_DumpMemory( FT_Memory  memory )
00924   {
00925     FT_MemTable  table = (FT_MemTable)memory->user;
00926 
00927 
00928     if ( table )
00929     {
00930       FT_MemSource*  bucket = table->sources;
00931       FT_MemSource*  limit  = bucket + FT_MEM_SOURCE_BUCKETS;
00932       FT_MemSource*  sources;
00933       FT_UInt        nn, count;
00934       const char*    fmt;
00935 
00936 
00937       count = 0;
00938       for ( ; bucket < limit; bucket++ )
00939       {
00940         FT_MemSource  source = *bucket;
00941 
00942 
00943         for ( ; source; source = source->link )
00944           count++;
00945       }
00946 
00947       sources = (FT_MemSource*)ft_mem_table_alloc(
00948                                  table, sizeof ( *sources ) * count );
00949 
00950       count = 0;
00951       for ( bucket = table->sources; bucket < limit; bucket++ )
00952       {
00953         FT_MemSource  source = *bucket;
00954 
00955 
00956         for ( ; source; source = source->link )
00957           sources[count++] = source;
00958       }
00959 
00960       ft_qsort( sources, count, sizeof ( *sources ), ft_mem_source_compare );
00961 
00962       printf( "FreeType Memory Dump: "
00963               "current=%ld max=%ld total=%ld count=%ld\n",
00964               table->alloc_current, table->alloc_max,
00965               table->alloc_total, table->alloc_count );
00966       printf( " block  block    sizes    sizes    sizes   source\n" );
00967       printf( " count   high      sum  highsum      max   location\n" );
00968       printf( "-------------------------------------------------\n" );
00969 
00970       fmt = "%6ld %6ld %8ld %8ld %8ld %s:%d\n";
00971 
00972       for ( nn = 0; nn < count; nn++ )
00973       {
00974         FT_MemSource  source = sources[nn];
00975 
00976 
00977         printf( fmt,
00978                 source->cur_blocks, source->max_blocks,
00979                 source->cur_size, source->max_size, source->cur_max,
00980                 FT_FILENAME( source->file_name ),
00981                 source->line_no );
00982       }
00983       printf( "------------------------------------------------\n" );
00984 
00985       ft_mem_table_free( table, sources );
00986     }
00987   }
00988 
00989 #else  /* !FT_DEBUG_MEMORY */
00990 
00991   /* ANSI C doesn't like empty source files */
00992   typedef int  _debug_mem_dummy;
00993 
00994 #endif /* !FT_DEBUG_MEMORY */
00995 
00996 
00997 /* END */

Generated on Tue Jul 5 14:13:42 2011 for ROOT_528-00b_version by  doxygen 1.5.1