source: trunk/poppler/freetype-2.1.10/src/base/ftdbgmem.c @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 15 years ago

First import

File size: 24.5 KB
Line 
1/***************************************************************************/
2/*                                                                         */
3/*  ftdbgmem.c                                                             */
4/*                                                                         */
5/*    Memory debugger (body).                                              */
6/*                                                                         */
7/*  Copyright 2001, 2002, 2003, 2004, 2005 by                              */
8/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9/*                                                                         */
10/*  This file is part of the FreeType project, and may only be used,       */
11/*  modified, and distributed under the terms of the FreeType project      */
12/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13/*  this file you indicate that you have read the license and              */
14/*  understand and accept it fully.                                        */
15/*                                                                         */
16/***************************************************************************/
17
18
19#include <ft2build.h>
20#include FT_CONFIG_CONFIG_H
21#include FT_INTERNAL_DEBUG_H
22#include FT_INTERNAL_MEMORY_H
23#include FT_SYSTEM_H
24#include FT_ERRORS_H
25#include FT_TYPES_H
26
27
28#ifdef FT_DEBUG_MEMORY
29
30#define  KEEPALIVE /* `Keep alive' means that freed blocks aren't released
31                    * to the heap.  This is useful to detect double-frees
32                    * or weird heap corruption, but it uses large amounts of
33                    * memory, however.
34                    */
35
36#include <stdio.h>
37#include <stdlib.h>
38
39
40  extern void
41  FT_DumpMemory( FT_Memory  memory );
42
43
44  typedef struct FT_MemSourceRec_*  FT_MemSource;
45  typedef struct FT_MemNodeRec_*    FT_MemNode;
46  typedef struct FT_MemTableRec_*   FT_MemTable;
47
48
49#define FT_MEM_VAL( addr )  ((FT_ULong)(FT_Pointer)( addr ))
50
51
52  typedef struct FT_MemSourceRec_
53  {
54    const char*   file_name;
55    long          line_no;
56
57    FT_Long       cur_blocks;   /* current number of allocated blocks */
58    FT_Long       max_blocks;   /* max. number of allocated blocks    */
59    FT_Long       all_blocks;   /* total number of blocks allocated   */
60
61    FT_Long       cur_size;     /* current cumulative allocated size */
62    FT_Long       max_size;     /* maximum cumulative allocated size */
63    FT_Long       all_size;     /* total cumulative allocated size   */
64
65    FT_Long       cur_max;      /* current maximum allocated size */
66
67    FT_UInt32     hash;
68    FT_MemSource  link;
69
70  } FT_MemSourceRec;
71
72
73/*
74 *  We don't need a resizable array for the memory sources, because
75 *  their number is pretty limited within FreeType.
76 */
77#define FT_MEM_SOURCE_BUCKETS  128
78
79
80  typedef struct  FT_MemNodeRec_
81  {
82    FT_Byte*      address;
83    FT_Long       size;     /* < 0 if the block was freed */
84
85    FT_MemSource  source;
86
87#ifdef KEEPALIVE
88    const char*   free_file_name;
89    FT_Long       free_line_no;
90#endif
91
92    FT_MemNode    link;
93
94  } FT_MemNodeRec;
95
96
97  typedef struct  FT_MemTableRec_
98  {
99    FT_ULong         size;
100    FT_ULong         nodes;
101    FT_MemNode*      buckets;
102
103    FT_ULong         alloc_total;
104    FT_ULong         alloc_current;
105    FT_ULong         alloc_max;
106    FT_ULong         alloc_count;
107
108    FT_Bool          bound_total;
109    FT_ULong         alloc_total_max;
110
111    FT_Bool          bound_count;
112    FT_ULong         alloc_count_max;
113
114    FT_MemSource     sources[FT_MEM_SOURCE_BUCKETS];
115
116    const char*      file_name;
117    FT_Long          line_no;
118
119    FT_Bool          keep_alive;
120
121    FT_Memory        memory;
122    FT_Pointer       memory_user;
123    FT_Alloc_Func    alloc;
124    FT_Free_Func     free;
125    FT_Realloc_Func  realloc;
126
127  } FT_MemTableRec;
128
129
130#define FT_MEM_SIZE_MIN  7
131#define FT_MEM_SIZE_MAX  13845163
132
133#define FT_FILENAME( x )  ((x) ? (x) : "unknown file")
134
135
136 /*
137  *  Prime numbers are ugly to handle.  It would be better to implement
138  *  L-Hashing, which is 10% faster and doesn't require divisions.
139  */
140  static const FT_UInt  ft_mem_primes[] =
141  {
142    7,
143    11,
144    19,
145    37,
146    73,
147    109,
148    163,
149    251,
150    367,
151    557,
152    823,
153    1237,
154    1861,
155    2777,
156    4177,
157    6247,
158    9371,
159    14057,
160    21089,
161    31627,
162    47431,
163    71143,
164    106721,
165    160073,
166    240101,
167    360163,
168    540217,
169    810343,
170    1215497,
171    1823231,
172    2734867,
173    4102283,
174    6153409,
175    9230113,
176    13845163,
177  };
178
179
180  static FT_ULong
181  ft_mem_closest_prime( FT_ULong  num )
182  {
183    FT_UInt  i;
184
185
186    for ( i = 0;
187          i < sizeof ( ft_mem_primes ) / sizeof ( ft_mem_primes[0] ); i++ )
188      if ( ft_mem_primes[i] > num )
189        return ft_mem_primes[i];
190
191    return FT_MEM_SIZE_MAX;
192  }
193
194
195  extern void
196  ft_mem_debug_panic( const char*  fmt,
197                      ... )
198  {
199    va_list  ap;
200
201
202    printf( "FreeType.Debug: " );
203
204    va_start( ap, fmt );
205    vprintf( fmt, ap );
206    va_end( ap );
207
208    printf( "\n" );
209    exit( EXIT_FAILURE );
210  }
211
212
213  static FT_Pointer
214  ft_mem_table_alloc( FT_MemTable  table,
215                      FT_Long      size )
216  {
217    FT_Memory   memory = table->memory;
218    FT_Pointer  block;
219
220
221    memory->user = table->memory_user;
222    block = table->alloc( memory, size );
223    memory->user = table;
224
225   return block;
226  }
227
228
229  static void
230  ft_mem_table_free( FT_MemTable  table,
231                     FT_Pointer   block )
232  {
233    FT_Memory  memory = table->memory;
234
235
236    memory->user = table->memory_user;
237    table->free( memory, block );
238    memory->user = table;
239  }
240
241
242  static void
243  ft_mem_table_resize( FT_MemTable  table )
244  {
245    FT_ULong  new_size;
246
247
248    new_size = ft_mem_closest_prime( table->nodes );
249    if ( new_size != table->size )
250    {
251      FT_MemNode*  new_buckets;
252      FT_ULong     i;
253
254
255      new_buckets = (FT_MemNode *)
256                      ft_mem_table_alloc( table,
257                                          new_size * sizeof ( FT_MemNode ) );
258      if ( new_buckets == NULL )
259        return;
260
261      FT_ARRAY_ZERO( new_buckets, new_size );
262
263      for ( i = 0; i < table->size; i++ )
264      {
265        FT_MemNode  node, next, *pnode;
266        FT_ULong    hash;
267
268
269        node = table->buckets[i];
270        while ( node )
271        {
272          next  = node->link;
273          hash  = FT_MEM_VAL( node->address ) % new_size;
274          pnode = new_buckets + hash;
275
276          node->link = pnode[0];
277          pnode[0]   = node;
278
279          node = next;
280        }
281      }
282
283      if ( table->buckets )
284        ft_mem_table_free( table, table->buckets );
285
286      table->buckets = new_buckets;
287      table->size    = new_size;
288    }
289  }
290
291
292  static FT_MemTable
293  ft_mem_table_new( FT_Memory  memory )
294  {
295    FT_MemTable  table;
296
297
298    table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) );
299    if ( table == NULL )
300      goto Exit;
301
302    FT_ZERO( table );
303
304    table->size  = FT_MEM_SIZE_MIN;
305    table->nodes = 0;
306
307    table->memory = memory;
308
309    table->memory_user = memory->user;
310
311    table->alloc   = memory->alloc;
312    table->realloc = memory->realloc;
313    table->free    = memory->free;
314
315    table->buckets = (FT_MemNode *)
316                       memory->alloc( memory,
317                                      table->size * sizeof ( FT_MemNode ) );
318    if ( table->buckets )
319      FT_ARRAY_ZERO( table->buckets, table->size );
320    else
321    {
322      memory->free( memory, table );
323      table = NULL;
324    }
325
326  Exit:
327    return table;
328  }
329
330
331  static void
332  ft_mem_table_destroy( FT_MemTable  table )
333  {
334    FT_ULong  i;
335
336
337    FT_DumpMemory( table->memory );
338
339    if ( table )
340    {
341      FT_Long    leak_count = 0;
342      FT_ULong   leaks = 0;
343
344      /* remove all blocks from the table, revealing leaked ones */
345      for ( i = 0; i < table->size; i++ )
346      {
347        FT_MemNode  *pnode = table->buckets + i, next, node = *pnode;
348
349
350        while ( node )
351        {
352          next       = node->link;
353          node->link = 0;
354
355          if ( node->size > 0 )
356          {
357            printf(
358              "leaked memory block at address %p, size %8ld in (%s:%ld)\n",
359              node->address, node->size,
360              FT_FILENAME( node->source->file_name ),
361              node->source->line_no );
362
363            leak_count++;
364            leaks += node->size;
365
366            ft_mem_table_free( table, node->address );
367          }
368
369          node->address = NULL;
370          node->size    = 0;
371
372          ft_mem_table_free( table, node );
373          node = next;
374        }
375        table->buckets[i] = 0;
376      }
377
378      ft_mem_table_free( table, table->buckets );
379      table->buckets = NULL;
380
381      table->size   = 0;
382      table->nodes  = 0;
383
384      /* remove all sources */
385      for ( i = 0; i < FT_MEM_SOURCE_BUCKETS; i++ )
386      {
387        FT_MemSource  source, next;
388
389
390        for ( source = table->sources[i]; source != NULL; source = next )
391        {
392          next = source->link;
393          ft_mem_table_free( table, source );
394        }
395
396        table->sources[i] = NULL;
397      }
398
399      printf(
400        "FreeType: total memory allocations = %ld\n", table->alloc_total );
401      printf(
402        "FreeType: maximum memory footprint = %ld\n", table->alloc_max );
403
404      ft_mem_table_free( table, table );
405
406      if ( leak_count > 0 )
407        ft_mem_debug_panic(
408          "FreeType: %ld bytes of memory leaked in %ld blocks\n",
409          leaks, leak_count );
410
411      printf( "FreeType: No memory leaks detected!\n" );
412    }
413  }
414
415
416  static FT_MemNode*
417  ft_mem_table_get_nodep( FT_MemTable  table,
418                          FT_Byte*     address )
419  {
420    FT_ULong     hash;
421    FT_MemNode  *pnode, node;
422
423
424    hash  = FT_MEM_VAL( address );
425    pnode = table->buckets + ( hash % table->size );
426
427    for (;;)
428    {
429      node = pnode[0];
430      if ( !node )
431        break;
432
433      if ( node->address == address )
434        break;
435
436      pnode = &node->link;
437    }
438    return pnode;
439  }
440
441
442  static FT_MemSource
443  ft_mem_table_get_source( FT_MemTable  table )
444  {
445    FT_UInt32     hash;
446    FT_MemSource  node, *pnode;
447
448
449    hash  = (FT_UInt32)(void*)table->file_name +
450              (FT_UInt32)( 5 * table->line_no );
451    pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS];
452
453    for ( ;; )
454    {
455      node = *pnode;
456      if ( node == NULL )
457        break;
458
459      if ( node->file_name == table->file_name &&
460           node->line_no   == table->line_no   )
461        goto Exit;
462
463      pnode = &node->link;
464    }
465
466    node = (FT_MemSource)ft_mem_table_alloc( table, sizeof ( *node ) );
467    if ( node == NULL )
468      ft_mem_debug_panic(
469        "not enough memory to perform memory debugging\n" );
470
471    node->file_name = table->file_name;
472    node->line_no   = table->line_no;
473
474    node->cur_blocks = 0;
475    node->max_blocks = 0;
476    node->all_blocks = 0;
477
478    node->cur_size   = 0;
479    node->max_size   = 0;
480    node->all_size   = 0;
481
482    node->cur_max    = 0;
483
484    node->link = NULL;
485    node->hash = hash;
486    *pnode     = node;
487
488  Exit:
489    return node;
490  }
491
492
493  static void
494  ft_mem_table_set( FT_MemTable  table,
495                    FT_Byte*     address,
496                    FT_ULong     size )
497  {
498    FT_MemNode  *pnode, node;
499
500
501    if ( table )
502    {
503      FT_MemSource  source;
504
505
506      pnode = ft_mem_table_get_nodep( table, address );
507      node  = *pnode;
508      if ( node )
509      {
510        if ( node->size < 0 )
511        {
512          /* This block was already freed.  Our memory is now completely */
513          /* corrupted!                                                  */
514          /* This can only happen in keep-alive mode.                    */
515          ft_mem_debug_panic(
516            "memory heap corrupted (allocating freed block)" );
517        }
518        else
519        {
520          /* This block was already allocated.  This means that our memory */
521          /* is also corrupted!                                            */
522          ft_mem_debug_panic(
523            "memory heap corrupted (re-allocating allocated block at"
524            " %p, of size %ld)\n"
525            "org=%s:%d new=%s:%d\n",
526            node->address, node->size,
527            FT_FILENAME( node->source->file_name ), node->source->line_no,
528            FT_FILENAME( table->file_name ), table->line_no );
529        }
530      }
531
532      /* we need to create a new node in this table */
533      node = (FT_MemNode)ft_mem_table_alloc( table, sizeof ( *node ) );
534      if ( node == NULL )
535        ft_mem_debug_panic( "not enough memory to run memory tests" );
536
537      node->address = address;
538      node->size    = size;
539
540      node->source = source = ft_mem_table_get_source( table );
541
542      source->all_blocks++;
543      source->cur_blocks++;
544      if ( source->cur_blocks > source->max_blocks )
545        source->max_blocks = source->cur_blocks;
546
547      if ( size > (FT_ULong)source->cur_max )
548        source->cur_max = size;
549
550      source->all_size += size;
551      source->cur_size += size;
552      if ( source->cur_size > source->max_size )
553        source->max_size = source->cur_size;
554
555      node->free_file_name = NULL;
556      node->free_line_no   = 0;
557
558      node->link = pnode[0];
559
560      pnode[0] = node;
561      table->nodes++;
562
563      table->alloc_total   += size;
564      table->alloc_current += size;
565      if ( table->alloc_current > table->alloc_max )
566        table->alloc_max = table->alloc_current;
567
568      if ( table->nodes * 3 < table->size  ||
569           table->size  * 3 < table->nodes )
570        ft_mem_table_resize( table );
571    }
572  }
573
574
575  static void
576  ft_mem_table_remove( FT_MemTable  table,
577                       FT_Byte*     address )
578  {
579    if ( table )
580    {
581      FT_MemNode  *pnode, node;
582
583
584      pnode = ft_mem_table_get_nodep( table, address );
585      node  = *pnode;
586      if ( node )
587      {
588        FT_MemSource  source;
589
590
591        if ( node->size < 0 )
592          ft_mem_debug_panic(
593            "freeing memory block at %p more than once at (%s:%ld)\n"
594            "block allocated at (%s:%ld) and released at (%s:%ld)",
595            address,
596            FT_FILENAME( table->file_name ), table->line_no,
597            FT_FILENAME( node->source->file_name ), node->source->line_no,
598            FT_FILENAME( node->free_file_name ), node->free_line_no );
599
600        /* scramble the node's content for additional safety */
601        FT_MEM_SET( address, 0xF3, node->size );
602        table->alloc_current -= node->size;
603
604        source = node->source;
605
606        source->cur_blocks--;
607        source->cur_size -= node->size;
608
609        if ( table->keep_alive )
610        {
611          /* we simply invert the node's size to indicate that the node */
612          /* was freed.                                                 */
613          node->size           = -node->size;
614          node->free_file_name = table->file_name;
615          node->free_line_no   = table->line_no;
616        }
617        else
618        {
619          table->nodes--;
620
621          *pnode = node->link;
622
623          node->size   = 0;
624          node->source = NULL;
625
626          ft_mem_table_free( table, node );
627
628          if ( table->nodes * 3 < table->size  ||
629               table->size  * 3 < table->nodes )
630            ft_mem_table_resize( table );
631        }
632      }
633      else
634        ft_mem_debug_panic(
635          "trying to free unknown block at %p in (%s:%ld)\n",
636          address,
637          FT_FILENAME( table->file_name ), table->line_no );
638    }
639  }
640
641
642  extern FT_Pointer
643  ft_mem_debug_alloc( FT_Memory  memory,
644                      FT_Long    size )
645  {
646    FT_MemTable  table = (FT_MemTable)memory->user;
647    FT_Byte*     block;
648
649
650    if ( size <= 0 )
651      ft_mem_debug_panic( "negative block size allocation (%ld)", size );
652
653    /* return NULL if the maximum number of allocations was reached */
654    if ( table->bound_count                           &&
655         table->alloc_count >= table->alloc_count_max )
656      return NULL;
657
658    /* return NULL if this allocation would overflow the maximum heap size */
659    if ( table->bound_total                                             &&
660         table->alloc_current + (FT_ULong)size > table->alloc_total_max )
661      return NULL;
662
663    block = (FT_Byte *)ft_mem_table_alloc( table, size );
664    if ( block )
665      ft_mem_table_set( table, block, (FT_ULong)size );
666
667    table->alloc_count++;
668
669    table->file_name = NULL;
670    table->line_no   = 0;
671
672    return (FT_Pointer)block;
673  }
674
675
676  extern void
677  ft_mem_debug_free( FT_Memory   memory,
678                     FT_Pointer  block )
679  {
680    FT_MemTable  table = (FT_MemTable)memory->user;
681
682
683    if ( block == NULL )
684      ft_mem_debug_panic( "trying to free NULL in (%s:%ld)",
685                          FT_FILENAME( table->file_name ),
686                          table->line_no );
687
688    ft_mem_table_remove( table, (FT_Byte*)block );
689
690    if ( !table->keep_alive )
691      ft_mem_table_free( table, block );
692
693    table->alloc_count--;
694
695    table->file_name = NULL;
696    table->line_no   = 0;
697  }
698
699
700  extern FT_Pointer
701  ft_mem_debug_realloc( FT_Memory   memory,
702                        FT_Long     cur_size,
703                        FT_Long     new_size,
704                        FT_Pointer  block )
705  {
706    FT_MemTable  table = (FT_MemTable)memory->user;
707    FT_MemNode   node, *pnode;
708    FT_Pointer   new_block;
709
710    const char*  file_name = FT_FILENAME( table->file_name );
711    FT_Long      line_no   = table->line_no;
712
713
714    /* the following is valid according to ANSI C */
715#if 0
716    if ( block == NULL || cur_size == 0 )
717      ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)",
718                          file_name, line_no );
719#endif
720
721    /* while the following is allowed in ANSI C also, we abort since */
722    /* such case should be handled by FreeType.                      */
723    if ( new_size <= 0 )
724      ft_mem_debug_panic(
725        "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)",
726        block, cur_size, file_name, line_no );
727
728    /* check `cur_size' value */
729    pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block );
730    node  = *pnode;
731    if ( !node )
732      ft_mem_debug_panic(
733        "trying to reallocate unknown block at %p in (%s:%ld)",
734        block, file_name, line_no );
735
736    if ( node->size <= 0 )
737      ft_mem_debug_panic(
738        "trying to reallocate freed block at %p in (%s:%ld)",
739        block, file_name, line_no );
740
741    if ( node->size != cur_size )
742      ft_mem_debug_panic( "invalid ft_realloc request for %p. cur_size is "
743                          "%ld instead of %ld in (%s:%ld)",
744                          block, cur_size, node->size, file_name, line_no );
745
746    new_block = ft_mem_debug_alloc( memory, new_size );
747    if ( new_block == NULL )
748      return NULL;
749
750    ft_memcpy( new_block, block, cur_size < new_size ? cur_size : new_size );
751
752    table->file_name = file_name;
753    table->line_no   = line_no;
754
755    ft_mem_debug_free( memory, (FT_Byte*)block );
756
757    return new_block;
758  }
759
760
761  extern FT_Int
762  ft_mem_debug_init( FT_Memory  memory )
763  {
764    FT_MemTable  table;
765    FT_Int       result = 0;
766
767
768    if ( getenv( "FT2_DEBUG_MEMORY" ) )
769    {
770      table = ft_mem_table_new( memory );
771      if ( table )
772      {
773        const char*  p;
774
775
776        memory->user    = table;
777        memory->alloc   = ft_mem_debug_alloc;
778        memory->realloc = ft_mem_debug_realloc;
779        memory->free    = ft_mem_debug_free;
780
781        p = getenv( "FT2_ALLOC_TOTAL_MAX" );
782        if ( p != NULL )
783        {
784          FT_Long   total_max = ft_atol( p );
785
786
787          if ( total_max > 0 )
788          {
789            table->bound_total     = 1;
790            table->alloc_total_max = (FT_ULong)total_max;
791          }
792        }
793
794        p = getenv( "FT2_ALLOC_COUNT_MAX" );
795        if ( p != NULL )
796        {
797          FT_Long  total_count = ft_atol( p );
798
799
800          if ( total_count > 0 )
801          {
802            table->bound_count     = 1;
803            table->alloc_count_max = (FT_ULong)total_count;
804          }
805        }
806
807        p = getenv( "FT2_KEEP_ALIVE" );
808        if ( p != NULL )
809        {
810          FT_Long  keep_alive = ft_atol( p );
811
812
813          if ( keep_alive > 0 )
814            table->keep_alive = 1;
815        }
816
817        result = 1;
818      }
819    }
820    return result;
821  }
822
823
824  extern void
825  ft_mem_debug_done( FT_Memory  memory )
826  {
827    FT_MemTable  table = (FT_MemTable)memory->user;
828
829
830    if ( table )
831    {
832      memory->free    = table->free;
833      memory->realloc = table->realloc;
834      memory->alloc   = table->alloc;
835
836      ft_mem_table_destroy( table );
837      memory->user = NULL;
838    }
839  }
840
841
842  FT_BASE_DEF( FT_Error )
843  FT_Alloc_Debug( FT_Memory    memory,
844                  FT_Long      size,
845                  void*       *P,
846                  const char*  file_name,
847                  FT_Long      line_no )
848  {
849    FT_MemTable  table = (FT_MemTable)memory->user;
850
851
852    if ( table )
853    {
854      table->file_name = file_name;
855      table->line_no   = line_no;
856    }
857
858    return FT_Alloc( memory, size, P );
859  }
860
861
862  FT_BASE_DEF( FT_Error )
863  FT_Realloc_Debug( FT_Memory    memory,
864                    FT_Long      current,
865                    FT_Long      size,
866                    void*       *P,
867                    const char*  file_name,
868                    FT_Long      line_no )
869  {
870    FT_MemTable  table = (FT_MemTable)memory->user;
871
872
873    if ( table )
874    {
875      table->file_name = file_name;
876      table->line_no   = line_no;
877    }
878
879    return FT_Realloc( memory, current, size, P );
880  }
881
882
883  FT_BASE_DEF( FT_Error )
884  FT_QAlloc_Debug( FT_Memory    memory,
885                   FT_Long      size,
886                   void*       *P,
887                   const char*  file_name,
888                   FT_Long      line_no )
889  {
890    FT_MemTable  table = (FT_MemTable)memory->user;
891
892
893    if ( table )
894    {
895      table->file_name = file_name;
896      table->line_no   = line_no;
897    }
898
899    return FT_QAlloc( memory, size, P );
900  }
901
902
903  FT_BASE_DEF( FT_Error )
904  FT_QRealloc_Debug( FT_Memory    memory,
905                     FT_Long      current,
906                     FT_Long      size,
907                     void*       *P,
908                     const char*  file_name,
909                     FT_Long      line_no )
910  {
911    FT_MemTable  table = (FT_MemTable)memory->user;
912
913
914    if ( table )
915    {
916      table->file_name = file_name;
917      table->line_no   = line_no;
918    }
919
920    return FT_QRealloc( memory, current, size, P );
921  }
922
923
924  FT_BASE_DEF( void )
925  FT_Free_Debug( FT_Memory    memory,
926                 FT_Pointer   block,
927                 const char*  file_name,
928                 FT_Long      line_no )
929  {
930    FT_MemTable  table = (FT_MemTable)memory->user;
931
932
933    if ( table )
934    {
935      table->file_name = file_name;
936      table->line_no   = line_no;
937    }
938
939    FT_Free( memory, (void **)block );
940  }
941
942
943  static int
944  ft_mem_source_compare( const void*  p1,
945                         const void*  p2 )
946  {
947    FT_MemSource  s1 = *(FT_MemSource*)p1;
948    FT_MemSource  s2 = *(FT_MemSource*)p2;
949
950
951    if ( s2->max_size > s1->max_size )
952      return 1;
953    else if ( s2->max_size < s1->max_size )
954      return -1;
955    else
956      return 0;
957  }
958
959
960  extern void
961  FT_DumpMemory( FT_Memory  memory )
962  {
963    FT_MemTable  table = (FT_MemTable)memory->user;
964
965
966    if ( table )
967    {
968      FT_MemSource*  bucket = table->sources;
969      FT_MemSource*  limit  = bucket + FT_MEM_SOURCE_BUCKETS;
970      FT_MemSource*  sources;
971      FT_UInt        nn, count;
972      const char*    fmt;
973
974
975      count = 0;
976      for ( ; bucket < limit; bucket++ )
977      {
978        FT_MemSource  source = *bucket;
979
980
981        for ( ; source; source = source->link )
982          count++;
983      }
984
985      sources = (FT_MemSource*)ft_mem_table_alloc(
986                                 table, sizeof ( *sources ) * count );
987
988      count = 0;
989      for ( bucket = table->sources; bucket < limit; bucket++ )
990      {
991        FT_MemSource  source = *bucket;
992
993
994        for ( ; source; source = source->link )
995          sources[count++] = source;
996      }
997
998      ft_qsort( sources, count, sizeof ( *sources ), ft_mem_source_compare );
999
1000      printf( "FreeType Memory Dump: "
1001              "current=%ld max=%ld total=%ld count=%ld\n",
1002              table->alloc_current, table->alloc_max,
1003              table->alloc_total, table->alloc_count );
1004      printf( " block  block    sizes    sizes    sizes   source\n" );
1005      printf( " count   high      sum  highsum      max   location\n" );
1006      printf( "-------------------------------------------------\n" );
1007
1008      fmt = "%6ld %6ld %8ld %8ld %8ld %s:%d\n";
1009
1010      for ( nn = 0; nn < count; nn++ )
1011      {
1012        FT_MemSource  source = sources[nn];
1013
1014
1015        printf( fmt,
1016                source->cur_blocks, source->max_blocks,
1017                source->cur_size, source->max_size, source->cur_max,
1018                FT_FILENAME( source->file_name ),
1019                source->line_no );
1020      }
1021      printf( "------------------------------------------------\n" );
1022
1023      ft_mem_table_free( table, sources );
1024    }
1025  }
1026
1027#else  /* !FT_DEBUG_MEMORY */
1028
1029  /* ANSI C doesn't like empty source files */
1030  const FT_Byte  _debug_mem_dummy = 0;
1031
1032#endif /* !FT_DEBUG_MEMORY */
1033
1034
1035/* END */
Note: See TracBrowser for help on using the repository browser.