20#include FT_CONFIG_CONFIG_H
36#include FT_CONFIG_STANDARD_LIBRARY_H
38 FT_BASE_DEF(
const char* ) ft_debug_file_ = NULL;
39 FT_BASE_DEF(
long ) ft_debug_lineno_ = 0;
42 FT_DumpMemory( FT_Memory memory );
45 typedef struct FT_MemSourceRec_* FT_MemSource;
46 typedef struct FT_MemNodeRec_* FT_MemNode;
47 typedef struct FT_MemTableRec_* FT_MemTable;
50#define FT_MEM_VAL( addr ) ( (FT_PtrDist)(FT_Pointer)( addr ) )
57 typedef struct FT_MemSourceRec_
59 const char* file_name;
82#define FT_MEM_SOURCE_BUCKETS 128
91 typedef struct FT_MemNodeRec_
99 const char* free_file_name;
100 FT_Long free_line_no;
112 typedef struct FT_MemTableRec_
119 FT_Long alloc_current;
124 FT_Long alloc_total_max;
127 FT_Long alloc_count_max;
129 FT_MemSource sources[FT_MEM_SOURCE_BUCKETS];
134 FT_Pointer memory_user;
137 FT_Realloc_Func realloc;
142#define FT_MEM_SIZE_MAX 13845163
144#define FT_FILENAME( x ) ( (x) ? (x) : "unknown file" )
151 static const FT_Int ft_mem_primes[] =
192 ft_mem_closest_prime( FT_Long num )
198 i <
sizeof ( ft_mem_primes ) /
sizeof ( ft_mem_primes[0] ); i++ )
199 if ( ft_mem_primes[i] > num )
200 return ft_mem_primes[i];
202 return FT_MEM_SIZE_MAX;
207 ft_mem_debug_panic(
const char* fmt,
213 printf(
"FreeType.Debug: " );
220 exit( EXIT_FAILURE );
225 ft_mem_table_alloc( FT_MemTable table,
228 FT_Memory memory = table->memory;
232 memory->user = table->memory_user;
233 block = table->alloc( memory, size );
234 memory->user = table;
241 ft_mem_table_free( FT_MemTable table,
244 FT_Memory memory = table->memory;
247 memory->user = table->memory_user;
248 table->free( memory, block );
249 memory->user = table;
254 ft_mem_table_resize( FT_MemTable table )
259 new_size = ft_mem_closest_prime( table->nodes );
260 if ( new_size != table->size )
262 FT_MemNode* new_buckets;
266 new_buckets = (FT_MemNode *)
269 new_size * (FT_Long)
sizeof ( FT_MemNode ) );
273 FT_ARRAY_ZERO( new_buckets, new_size );
275 for ( i = 0; i < table->size; i++ )
277 FT_MemNode node, next, *pnode;
281 node = table->buckets[i];
285 hash = FT_MEM_VAL( node->address ) % (FT_PtrDist)new_size;
286 pnode = new_buckets + hash;
288 node->link = pnode[0];
295 if ( table->buckets )
296 ft_mem_table_free( table, table->buckets );
298 table->buckets = new_buckets;
299 table->size = new_size;
305 ft_mem_table_destroy( FT_MemTable table )
308 FT_Long leak_count = 0;
313 for ( i = 0; i < table->size; i++ )
315 FT_MemNode *pnode = table->buckets + i, next, node = *pnode;
323 if ( node->size > 0 )
326 "leaked memory block at address %p, size %8ld in (%s:%ld)\n",
327 (
void*)node->address,
329 FT_FILENAME( node->source->file_name ),
330 node->source->line_no );
335 ft_mem_table_free( table, node->address );
338 node->address = NULL;
341 ft_mem_table_free( table, node );
344 table->buckets[i] = NULL;
347 ft_mem_table_free( table, table->buckets );
348 table->buckets = NULL;
354 for ( i = 0; i < FT_MEM_SOURCE_BUCKETS; i++ )
356 FT_MemSource source, next;
359 for ( source = table->sources[i]; source != NULL; source = next )
362 ft_mem_table_free( table, source );
365 table->sources[i] = NULL;
368 printf(
"FreeType: total memory allocations = %ld\n",
369 table->alloc_total );
370 printf(
"FreeType: maximum memory footprint = %ld\n",
373 if ( leak_count > 0 )
375 "FreeType: %ld bytes of memory leaked in %ld blocks\n",
378 printf(
"FreeType: no memory leaks detected\n" );
383 ft_mem_table_get_nodep( FT_MemTable table,
387 FT_MemNode *pnode, node;
390 hash = FT_MEM_VAL( address );
391 pnode = table->buckets + ( hash % (FT_PtrDist)table->size );
399 if ( node->address == address )
409 ft_mem_table_get_source( FT_MemTable table )
412 FT_MemSource node, *pnode;
417 hash = (FT_UInt32)(FT_PtrDist)(
void*)ft_debug_file_ +
418 (FT_UInt32)( 5 * ft_debug_lineno_ );
419 pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS];
427 if ( node->file_name == ft_debug_file_ &&
428 node->line_no == ft_debug_lineno_ )
434 node = (FT_MemSource)ft_mem_table_alloc( table,
sizeof ( *node ) );
437 "not enough memory to perform memory debugging\n" );
439 node->file_name = ft_debug_file_;
440 node->line_no = ft_debug_lineno_;
442 node->cur_blocks = 0;
443 node->max_blocks = 0;
444 node->all_blocks = 0;
462 ft_mem_table_set( FT_MemTable table,
467 FT_MemNode *pnode, node;
475 pnode = ft_mem_table_get_nodep( table, address );
479 if ( node->size < 0 )
485 "memory heap corrupted (allocating freed block)" );
492 "memory heap corrupted (re-allocating allocated block at"
493 " %p, of size %ld)\n"
494 "org=%s:%d new=%s:%d\n",
495 node->address, node->size,
496 FT_FILENAME( node->source->file_name ), node->source->line_no,
497 FT_FILENAME( ft_debug_file_ ), ft_debug_lineno_ );
502 node = (FT_MemNode)ft_mem_table_alloc( table,
sizeof ( *node ) );
504 ft_mem_debug_panic(
"not enough memory to run memory tests" );
506 node->address = address;
508 node->source = source = ft_mem_table_get_source( table );
513 source->all_blocks++;
514 source->cur_blocks++;
515 if ( source->cur_blocks > source->max_blocks )
516 source->max_blocks = source->cur_blocks;
519 if ( size > source->cur_max )
520 source->cur_max = size;
525 source->cur_size += delta;
526 table->alloc_current += delta;
531 source->cur_size += size;
532 table->alloc_current += size;
535 source->all_size += size;
537 if ( source->cur_size > source->max_size )
538 source->max_size = source->cur_size;
540 node->free_file_name = NULL;
541 node->free_line_no = 0;
543 node->link = pnode[0];
548 table->alloc_total += size;
550 if ( table->alloc_current > table->alloc_max )
551 table->alloc_max = table->alloc_current;
553 if ( table->nodes * 3 < table->size ||
554 table->size * 3 < table->nodes )
555 ft_mem_table_resize( table );
561 ft_mem_table_remove( FT_MemTable table,
567 FT_MemNode *pnode, node;
570 pnode = ft_mem_table_get_nodep( table, address );
577 if ( node->size < 0 )
579 "freeing memory block at %p more than once\n"
581 " Block was allocated at (%s:%ld)\n"
582 " and released at (%s:%ld).",
584 FT_FILENAME( ft_debug_file_ ), ft_debug_lineno_,
585 FT_FILENAME( node->source->file_name ), node->source->line_no,
586 FT_FILENAME( node->free_file_name ), node->free_line_no );
589 FT_MEM_SET( address, 0xF3, node->size );
593 source = node->source;
595 source->cur_blocks--;
596 source->cur_size -= node->size;
598 table->alloc_current -= node->size;
601 if ( table->keep_alive )
605 node->size = -node->size;
606 node->free_file_name = ft_debug_file_;
607 node->free_line_no = ft_debug_lineno_;
618 ft_mem_table_free( table, node );
620 if ( table->nodes * 3 < table->size ||
621 table->size * 3 < table->nodes )
622 ft_mem_table_resize( table );
627 "trying to free unknown block at %p in (%s:%ld)\n",
629 FT_FILENAME( ft_debug_file_ ), ft_debug_lineno_ );
635 ft_mem_debug_alloc( FT_Memory memory,
638 FT_MemTable table = (FT_MemTable)memory->user;
643 ft_mem_debug_panic(
"negative block size allocation (%ld)", size );
646 if ( table->bound_count &&
647 table->alloc_count >= table->alloc_count_max )
651 if ( table->bound_total &&
652 table->alloc_total_max - table->alloc_current > size )
655 block = (FT_Byte *)ft_mem_table_alloc( table, size );
658 ft_mem_table_set( table, block, size, 0 );
660 table->alloc_count++;
663 ft_debug_file_ =
"<unknown>";
664 ft_debug_lineno_ = 0;
666 return (FT_Pointer)block;
671 ft_mem_debug_free( FT_Memory memory,
674 FT_MemTable table = (FT_MemTable)memory->user;
678 ft_mem_debug_panic(
"trying to free NULL in (%s:%ld)",
679 FT_FILENAME( ft_debug_file_ ),
682 ft_mem_table_remove( table, (FT_Byte*)block, 0 );
684 if ( !table->keep_alive )
685 ft_mem_table_free( table, block );
687 table->alloc_count--;
689 ft_debug_file_ =
"<unknown>";
690 ft_debug_lineno_ = 0;
695 ft_mem_debug_realloc( FT_Memory memory,
700 FT_MemTable table = (FT_MemTable)memory->user;
701 FT_MemNode node, *pnode;
702 FT_Pointer new_block;
705 const char* file_name = FT_FILENAME( ft_debug_file_ );
706 FT_Long line_no = ft_debug_lineno_;
710 if ( new_size == cur_size )
715 if ( !block || !cur_size )
716 ft_mem_debug_panic(
"trying to reallocate NULL in (%s:%ld)",
717 file_name, line_no );
724 "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)",
725 block, cur_size, file_name, line_no );
728 pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block );
732 "trying to reallocate unknown block at %p in (%s:%ld)",
733 block, file_name, line_no );
735 if ( node->size <= 0 )
737 "trying to reallocate freed block at %p in (%s:%ld)",
738 block, file_name, line_no );
740 if ( node->size != cur_size )
741 ft_mem_debug_panic(
"invalid ft_realloc request for %p. cur_size is "
742 "%ld instead of %ld in (%s:%ld)",
743 block, cur_size, node->size, file_name, line_no );
746 if ( table->bound_count &&
747 table->alloc_count >= table->alloc_count_max )
750 delta = new_size - cur_size;
754 table->bound_total &&
755 table->alloc_current + delta > table->alloc_total_max )
758 new_block = (FT_Pointer)ft_mem_table_alloc( table, new_size );
762 ft_mem_table_set( table, (FT_Byte*)new_block, new_size, delta );
764 ft_memcpy( new_block, block, cur_size < new_size ? (
size_t)cur_size
765 : (
size_t)new_size );
767 ft_mem_table_remove( table, (FT_Byte*)block, delta );
769 ft_debug_file_ =
"<unknown>";
770 ft_debug_lineno_ = 0;
772 if ( !table->keep_alive )
773 ft_mem_table_free( table, block );
780 ft_mem_debug_init( FT_Memory memory )
785 if ( !ft_getenv(
"FT2_DEBUG_MEMORY" ) )
788 table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) );
794 table->memory = memory;
795 table->memory_user = memory->user;
796 table->alloc = memory->alloc;
797 table->realloc = memory->realloc;
798 table->free = memory->free;
800 ft_mem_table_resize( table );
807 memory->user = table;
808 memory->alloc = ft_mem_debug_alloc;
809 memory->realloc = ft_mem_debug_realloc;
810 memory->free = ft_mem_debug_free;
812 p = ft_getenv(
"FT2_ALLOC_TOTAL_MAX" );
815 FT_Long total_max = ft_strtol( p, NULL, 10 );
820 table->bound_total = 1;
821 table->alloc_total_max = total_max;
825 p = ft_getenv(
"FT2_ALLOC_COUNT_MAX" );
828 FT_Long total_count = ft_strtol( p, NULL, 10 );
831 if ( total_count > 0 )
833 table->bound_count = 1;
834 table->alloc_count_max = total_count;
838 p = ft_getenv(
"FT2_KEEP_ALIVE" );
841 FT_Long keep_alive = ft_strtol( p, NULL, 10 );
844 if ( keep_alive > 0 )
845 table->keep_alive = 1;
849 memory->free( memory, table );
855 ft_mem_debug_done( FT_Memory memory )
857 if ( memory->free == ft_mem_debug_free )
859 FT_MemTable table = (FT_MemTable)memory->user;
862 FT_DumpMemory( memory );
864 ft_mem_table_destroy( table );
866 memory->free = table->free;
867 memory->realloc = table->realloc;
868 memory->alloc = table->alloc;
869 memory->user = table->memory_user;
871 memory->free( memory, table );
876 FT_COMPARE_DEF(
int )
877 ft_mem_source_compare(
const void* p1,
880 FT_MemSource s1 = *(FT_MemSource*)p1;
881 FT_MemSource s2 = *(FT_MemSource*)p2;
884 if ( s2->max_size > s1->max_size )
886 else if ( s2->max_size < s1->max_size )
894 FT_DumpMemory( FT_Memory memory )
896 if ( memory->free == ft_mem_debug_free )
898 FT_MemTable table = (FT_MemTable)memory->user;
899 FT_MemSource* bucket = table->sources;
900 FT_MemSource* limit = bucket + FT_MEM_SOURCE_BUCKETS;
901 FT_MemSource* sources;
907 for ( ; bucket < limit; bucket++ )
909 FT_MemSource source = *bucket;
912 for ( ; source; source = source->link )
916 sources = (FT_MemSource*)
918 table, count * (FT_Long)
sizeof ( *sources ) );
921 for ( bucket = table->sources; bucket < limit; bucket++ )
923 FT_MemSource source = *bucket;
926 for ( ; source; source = source->link )
927 sources[count++] = source;
933 ft_mem_source_compare );
935 printf(
"FreeType Memory Dump: "
936 "current=%ld max=%ld total=%ld count=%ld\n",
937 table->alloc_current, table->alloc_max,
938 table->alloc_total, table->alloc_count );
939 printf(
" block block sizes sizes sizes source\n" );
940 printf(
" count high sum highsum max location\n" );
941 printf(
"-------------------------------------------------\n" );
943 fmt =
"%6ld %6ld %8ld %8ld %8ld %s:%d\n";
945 for ( nn = 0; nn < count; nn++ )
947 FT_MemSource source = sources[nn];
951 source->cur_blocks, source->max_blocks,
952 source->cur_size, source->max_size, source->cur_max,
953 FT_FILENAME( source->file_name ),
956 printf(
"------------------------------------------------\n" );
958 ft_mem_table_free( table, sources );
965 typedef int debug_mem_dummy_;