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