Visualization Library 2.0.0-b5

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

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