Deprecate g_thread_init()
[platform/upstream/glib.git] / glib / gmem.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GLib Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 /* 
28  * MT safe
29  */
30
31 #include "config.h"
32
33 #include "gmem.h"
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <signal.h>
38
39 #include "glib-init.h"
40
41 #include "gslice.h"
42 #include "gbacktrace.h"
43 #include "gtestutils.h"
44 #include "gthread.h"
45 #include "glib_trace.h"
46 #include "glib-ctor.h"
47
48
49 #define MEM_PROFILE_TABLE_SIZE 4096
50
51
52 /* notes on macros:
53  * having G_DISABLE_CHECKS defined disables use of glib_mem_profiler_table and
54  * g_mem_profile().
55  * REALLOC_0_WORKS is defined if g_realloc (NULL, x) works.
56  * SANE_MALLOC_PROTOS is defined if the systems malloc() and friends functions
57  * match the corresponding GLib prototypes, keep configure.ac and gmem.h in sync here.
58  * g_mem_gc_friendly is TRUE, freed memory should be 0-wiped.
59  */
60
61 /* --- malloc wrappers --- */
62 #ifndef REALLOC_0_WORKS
63 static gpointer
64 standard_realloc (gpointer mem,
65                   gsize    n_bytes)
66 {
67   if (!mem)
68     return malloc (n_bytes);
69   else
70     return realloc (mem, n_bytes);
71 }
72 #endif  /* !REALLOC_0_WORKS */
73
74 #ifdef SANE_MALLOC_PROTOS
75 #  define standard_malloc       malloc
76 #  ifdef REALLOC_0_WORKS
77 #    define standard_realloc    realloc
78 #  endif /* REALLOC_0_WORKS */
79 #  define standard_free         free
80 #  define standard_calloc       calloc
81 #  define standard_try_malloc   malloc
82 #  define standard_try_realloc  realloc
83 #else   /* !SANE_MALLOC_PROTOS */
84 static gpointer
85 standard_malloc (gsize n_bytes)
86 {
87   return malloc (n_bytes);
88 }
89 #  ifdef REALLOC_0_WORKS
90 static gpointer
91 standard_realloc (gpointer mem,
92                   gsize    n_bytes)
93 {
94   return realloc (mem, n_bytes);
95 }
96 #  endif /* REALLOC_0_WORKS */
97 static void
98 standard_free (gpointer mem)
99 {
100   free (mem);
101 }
102 static gpointer
103 standard_calloc (gsize n_blocks,
104                  gsize n_bytes)
105 {
106   return calloc (n_blocks, n_bytes);
107 }
108 #define standard_try_malloc     standard_malloc
109 #define standard_try_realloc    standard_realloc
110 #endif  /* !SANE_MALLOC_PROTOS */
111
112
113 /* --- variables --- */
114 static GMemVTable glib_mem_vtable = {
115   standard_malloc,
116   standard_realloc,
117   standard_free,
118   standard_calloc,
119   standard_try_malloc,
120   standard_try_realloc,
121 };
122
123 /**
124  * SECTION:memory
125  * @Short_Description: general memory-handling
126  * @Title: Memory Allocation
127  * 
128  * These functions provide support for allocating and freeing memory.
129  * 
130  * <note>
131  * If any call to allocate memory fails, the application is terminated.
132  * This also means that there is no need to check if the call succeeded.
133  * </note>
134  * 
135  * <note>
136  * It's important to match g_malloc() with g_free(), plain malloc() with free(),
137  * and (if you're using C++) new with delete and new[] with delete[]. Otherwise
138  * bad things can happen, since these allocators may use different memory
139  * pools (and new/delete call constructors and destructors). See also
140  * g_mem_set_vtable().
141  * </note>
142  */
143
144 /* --- functions --- */
145 /**
146  * g_malloc:
147  * @n_bytes: the number of bytes to allocate
148  * 
149  * Allocates @n_bytes bytes of memory.
150  * If @n_bytes is 0 it returns %NULL.
151  * 
152  * Returns: a pointer to the allocated memory
153  */
154 gpointer
155 g_malloc (gsize n_bytes)
156 {
157   if (G_LIKELY (n_bytes))
158     {
159       gpointer mem;
160
161       mem = glib_mem_vtable.malloc (n_bytes);
162       TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 0, 0));
163       if (mem)
164         return mem;
165
166       g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
167                G_STRLOC, n_bytes);
168     }
169
170   TRACE(GLIB_MEM_ALLOC((void*) NULL, (int) n_bytes, 0, 0));
171
172   return NULL;
173 }
174
175 /**
176  * g_malloc0:
177  * @n_bytes: the number of bytes to allocate
178  * 
179  * Allocates @n_bytes bytes of memory, initialized to 0's.
180  * If @n_bytes is 0 it returns %NULL.
181  * 
182  * Returns: a pointer to the allocated memory
183  */
184 gpointer
185 g_malloc0 (gsize n_bytes)
186 {
187   if (G_LIKELY (n_bytes))
188     {
189       gpointer mem;
190
191       mem = glib_mem_vtable.calloc (1, n_bytes);
192       TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 1, 0));
193       if (mem)
194         return mem;
195
196       g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
197                G_STRLOC, n_bytes);
198     }
199
200   TRACE(GLIB_MEM_ALLOC((void*) NULL, (int) n_bytes, 1, 0));
201
202   return NULL;
203 }
204
205 /**
206  * g_realloc:
207  * @mem: the memory to reallocate
208  * @n_bytes: new size of the memory in bytes
209  * 
210  * Reallocates the memory pointed to by @mem, so that it now has space for
211  * @n_bytes bytes of memory. It returns the new address of the memory, which may
212  * have been moved. @mem may be %NULL, in which case it's considered to
213  * have zero-length. @n_bytes may be 0, in which case %NULL will be returned
214  * and @mem will be freed unless it is %NULL.
215  * 
216  * Returns: the new address of the allocated memory
217  */
218 gpointer
219 g_realloc (gpointer mem,
220            gsize    n_bytes)
221 {
222   gpointer newmem;
223
224   if (G_LIKELY (n_bytes))
225     {
226       newmem = glib_mem_vtable.realloc (mem, n_bytes);
227       TRACE (GLIB_MEM_REALLOC((void*) newmem, (void*)mem, (unsigned int) n_bytes, 0));
228       if (newmem)
229         return newmem;
230
231       g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
232                G_STRLOC, n_bytes);
233     }
234
235   if (mem)
236     glib_mem_vtable.free (mem);
237
238   TRACE (GLIB_MEM_REALLOC((void*) NULL, (void*)mem, 0, 0));
239
240   return NULL;
241 }
242
243 /**
244  * g_free:
245  * @mem: the memory to free
246  * 
247  * Frees the memory pointed to by @mem.
248  * If @mem is %NULL it simply returns.
249  */
250 void
251 g_free (gpointer mem)
252 {
253   if (G_LIKELY (mem))
254     glib_mem_vtable.free (mem);
255   TRACE(GLIB_MEM_FREE((void*) mem));
256 }
257
258 /**
259  * g_try_malloc:
260  * @n_bytes: number of bytes to allocate.
261  * 
262  * Attempts to allocate @n_bytes, and returns %NULL on failure.
263  * Contrast with g_malloc(), which aborts the program on failure.
264  * 
265  * Returns: the allocated memory, or %NULL.
266  */
267 gpointer
268 g_try_malloc (gsize n_bytes)
269 {
270   gpointer mem;
271
272   if (G_LIKELY (n_bytes))
273     mem = glib_mem_vtable.try_malloc (n_bytes);
274   else
275     mem = NULL;
276
277   TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 0, 1));
278
279   return mem;
280 }
281
282 /**
283  * g_try_malloc0:
284  * @n_bytes: number of bytes to allocate
285  * 
286  * Attempts to allocate @n_bytes, initialized to 0's, and returns %NULL on
287  * failure. Contrast with g_malloc0(), which aborts the program on failure.
288  * 
289  * Since: 2.8
290  * Returns: the allocated memory, or %NULL
291  */
292 gpointer
293 g_try_malloc0 (gsize n_bytes)
294 {
295   gpointer mem;
296
297   if (G_LIKELY (n_bytes))
298     mem = glib_mem_vtable.try_malloc (n_bytes);
299   else
300     mem = NULL;
301
302   if (mem)
303     memset (mem, 0, n_bytes);
304
305   return mem;
306 }
307
308 /**
309  * g_try_realloc:
310  * @mem: previously-allocated memory, or %NULL.
311  * @n_bytes: number of bytes to allocate.
312  * 
313  * Attempts to realloc @mem to a new size, @n_bytes, and returns %NULL
314  * on failure. Contrast with g_realloc(), which aborts the program
315  * on failure. If @mem is %NULL, behaves the same as g_try_malloc().
316  * 
317  * Returns: the allocated memory, or %NULL.
318  */
319 gpointer
320 g_try_realloc (gpointer mem,
321                gsize    n_bytes)
322 {
323   gpointer newmem;
324
325   if (G_LIKELY (n_bytes))
326     newmem = glib_mem_vtable.try_realloc (mem, n_bytes);
327   else
328     {
329       newmem = NULL;
330       if (mem)
331         glib_mem_vtable.free (mem);
332     }
333
334   TRACE (GLIB_MEM_REALLOC((void*) newmem, (void*)mem, (unsigned int) n_bytes, 1));
335
336   return newmem;
337 }
338
339
340 #define SIZE_OVERFLOWS(a,b) (G_UNLIKELY ((b) > 0 && (a) > G_MAXSIZE / (b)))
341
342 /**
343  * g_malloc_n:
344  * @n_blocks: the number of blocks to allocate
345  * @n_block_bytes: the size of each block in bytes
346  * 
347  * This function is similar to g_malloc(), allocating (@n_blocks * @n_block_bytes) bytes,
348  * but care is taken to detect possible overflow during multiplication.
349  * 
350  * Since: 2.24
351  * Returns: a pointer to the allocated memory
352  */
353 gpointer
354 g_malloc_n (gsize n_blocks,
355             gsize n_block_bytes)
356 {
357   if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
358     {
359       g_error ("%s: overflow allocating %"G_GSIZE_FORMAT"*%"G_GSIZE_FORMAT" bytes",
360                G_STRLOC, n_blocks, n_block_bytes);
361     }
362
363   return g_malloc (n_blocks * n_block_bytes);
364 }
365
366 /**
367  * g_malloc0_n:
368  * @n_blocks: the number of blocks to allocate
369  * @n_block_bytes: the size of each block in bytes
370  * 
371  * This function is similar to g_malloc0(), allocating (@n_blocks * @n_block_bytes) bytes,
372  * but care is taken to detect possible overflow during multiplication.
373  * 
374  * Since: 2.24
375  * Returns: a pointer to the allocated memory
376  */
377 gpointer
378 g_malloc0_n (gsize n_blocks,
379              gsize n_block_bytes)
380 {
381   if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
382     {
383       g_error ("%s: overflow allocating %"G_GSIZE_FORMAT"*%"G_GSIZE_FORMAT" bytes",
384                G_STRLOC, n_blocks, n_block_bytes);
385     }
386
387   return g_malloc0 (n_blocks * n_block_bytes);
388 }
389
390 /**
391  * g_realloc_n:
392  * @mem: the memory to reallocate
393  * @n_blocks: the number of blocks to allocate
394  * @n_block_bytes: the size of each block in bytes
395  * 
396  * This function is similar to g_realloc(), allocating (@n_blocks * @n_block_bytes) bytes,
397  * but care is taken to detect possible overflow during multiplication.
398  * 
399  * Since: 2.24
400  * Returns: the new address of the allocated memory
401  */
402 gpointer
403 g_realloc_n (gpointer mem,
404              gsize    n_blocks,
405              gsize    n_block_bytes)
406 {
407   if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
408     {
409       g_error ("%s: overflow allocating %"G_GSIZE_FORMAT"*%"G_GSIZE_FORMAT" bytes",
410                G_STRLOC, n_blocks, n_block_bytes);
411     }
412
413   return g_realloc (mem, n_blocks * n_block_bytes);
414 }
415
416 /**
417  * g_try_malloc_n:
418  * @n_blocks: the number of blocks to allocate
419  * @n_block_bytes: the size of each block in bytes
420  * 
421  * This function is similar to g_try_malloc(), allocating (@n_blocks * @n_block_bytes) bytes,
422  * but care is taken to detect possible overflow during multiplication.
423  * 
424  * Since: 2.24
425  * Returns: the allocated memory, or %NULL.
426  */
427 gpointer
428 g_try_malloc_n (gsize n_blocks,
429                 gsize n_block_bytes)
430 {
431   if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
432     return NULL;
433
434   return g_try_malloc (n_blocks * n_block_bytes);
435 }
436
437 /**
438  * g_try_malloc0_n:
439  * @n_blocks: the number of blocks to allocate
440  * @n_block_bytes: the size of each block in bytes
441  * 
442  * This function is similar to g_try_malloc0(), allocating (@n_blocks * @n_block_bytes) bytes,
443  * but care is taken to detect possible overflow during multiplication.
444  * 
445  * Since: 2.24
446  * Returns: the allocated memory, or %NULL
447  */
448 gpointer
449 g_try_malloc0_n (gsize n_blocks,
450                  gsize n_block_bytes)
451 {
452   if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
453     return NULL;
454
455   return g_try_malloc0 (n_blocks * n_block_bytes);
456 }
457
458 /**
459  * g_try_realloc_n:
460  * @mem: previously-allocated memory, or %NULL.
461  * @n_blocks: the number of blocks to allocate
462  * @n_block_bytes: the size of each block in bytes
463  * 
464  * This function is similar to g_try_realloc(), allocating (@n_blocks * @n_block_bytes) bytes,
465  * but care is taken to detect possible overflow during multiplication.
466  * 
467  * Since: 2.24
468  * Returns: the allocated memory, or %NULL.
469  */
470 gpointer
471 g_try_realloc_n (gpointer mem,
472                  gsize    n_blocks,
473                  gsize    n_block_bytes)
474 {
475   if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
476     return NULL;
477
478   return g_try_realloc (mem, n_blocks * n_block_bytes);
479 }
480
481
482
483 static gpointer
484 fallback_calloc (gsize n_blocks,
485                  gsize n_block_bytes)
486 {
487   gsize l = n_blocks * n_block_bytes;
488   gpointer mem = glib_mem_vtable.malloc (l);
489
490   if (mem)
491     memset (mem, 0, l);
492
493   return mem;
494 }
495
496 static gboolean vtable_set = FALSE;
497
498 /**
499  * g_mem_is_system_malloc
500  * 
501  * Checks whether the allocator used by g_malloc() is the system's
502  * malloc implementation. If it returns %TRUE memory allocated with
503  * malloc() can be used interchangeable with memory allocated using g_malloc().
504  * This function is useful for avoiding an extra copy of allocated memory returned
505  * by a non-GLib-based API.
506  *
507  * A different allocator can be set using g_mem_set_vtable().
508  *
509  * Return value: if %TRUE, malloc() and g_malloc() can be mixed.
510  **/
511 gboolean
512 g_mem_is_system_malloc (void)
513 {
514   return !vtable_set;
515 }
516
517 /**
518  * g_mem_set_vtable:
519  * @vtable: table of memory allocation routines.
520  * 
521  * Sets the #GMemVTable to use for memory allocation. You can use this to provide
522  * custom memory allocation routines. <emphasis>This function must be called
523  * before using any other GLib functions.</emphasis> The @vtable only needs to
524  * provide malloc(), realloc(), and free() functions; GLib can provide default
525  * implementations of the others. The malloc() and realloc() implementations
526  * should return %NULL on failure, GLib will handle error-checking for you.
527  * @vtable is copied, so need not persist after this function has been called.
528  */
529 void
530 g_mem_set_vtable (GMemVTable *vtable)
531 {
532   if (!vtable_set)
533     {
534       if (vtable->malloc && vtable->realloc && vtable->free)
535         {
536           glib_mem_vtable.malloc = vtable->malloc;
537           glib_mem_vtable.realloc = vtable->realloc;
538           glib_mem_vtable.free = vtable->free;
539           glib_mem_vtable.calloc = vtable->calloc ? vtable->calloc : fallback_calloc;
540           glib_mem_vtable.try_malloc = vtable->try_malloc ? vtable->try_malloc : glib_mem_vtable.malloc;
541           glib_mem_vtable.try_realloc = vtable->try_realloc ? vtable->try_realloc : glib_mem_vtable.realloc;
542           vtable_set = TRUE;
543         }
544       else
545         g_warning (G_STRLOC ": memory allocation vtable lacks one of malloc(), realloc() or free()");
546     }
547   else
548     g_warning (G_STRLOC ": memory allocation vtable can only be set once at startup");
549 }
550
551
552 /* --- memory profiling and checking --- */
553 #ifdef  G_DISABLE_CHECKS
554 /**
555  * glib_mem_profiler_table:
556  * 
557  * A #GMemVTable containing profiling variants of the memory
558  * allocation functions. Use them together with g_mem_profile()
559  * in order to get information about the memory allocation pattern
560  * of your program.
561  */
562 GMemVTable *glib_mem_profiler_table = &glib_mem_vtable;
563 void
564 g_mem_profile (void)
565 {
566 }
567 #else   /* !G_DISABLE_CHECKS */
568 typedef enum {
569   PROFILER_FREE         = 0,
570   PROFILER_ALLOC        = 1,
571   PROFILER_RELOC        = 2,
572   PROFILER_ZINIT        = 4
573 } ProfilerJob;
574 static guint *profile_data = NULL;
575 static gsize profile_allocs = 0;
576 static gsize profile_zinit = 0;
577 static gsize profile_frees = 0;
578 static GMutex gmem_profile_mutex;
579 #ifdef  G_ENABLE_DEBUG
580 static volatile gsize g_trap_free_size = 0;
581 static volatile gsize g_trap_realloc_size = 0;
582 static volatile gsize g_trap_malloc_size = 0;
583 #endif  /* G_ENABLE_DEBUG */
584
585 #define PROFILE_TABLE(f1,f2,f3)   ( ( ((f3) << 2) | ((f2) << 1) | (f1) ) * (MEM_PROFILE_TABLE_SIZE + 1))
586
587 static void
588 profiler_log (ProfilerJob job,
589               gsize       n_bytes,
590               gboolean    success)
591 {
592   g_mutex_lock (&gmem_profile_mutex);
593   if (!profile_data)
594     {
595       profile_data = standard_calloc ((MEM_PROFILE_TABLE_SIZE + 1) * 8, 
596                                       sizeof (profile_data[0]));
597       if (!profile_data)        /* memory system kiddin' me, eh? */
598         {
599           g_mutex_unlock (&gmem_profile_mutex);
600           return;
601         }
602     }
603
604   if (n_bytes < MEM_PROFILE_TABLE_SIZE)
605     profile_data[n_bytes + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0,
606                                           (job & PROFILER_RELOC) != 0,
607                                           success != 0)] += 1;
608   else
609     profile_data[MEM_PROFILE_TABLE_SIZE + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0,
610                                                          (job & PROFILER_RELOC) != 0,
611                                                          success != 0)] += 1;
612   if (success)
613     {
614       if (job & PROFILER_ALLOC)
615         {
616           profile_allocs += n_bytes;
617           if (job & PROFILER_ZINIT)
618             profile_zinit += n_bytes;
619         }
620       else
621         profile_frees += n_bytes;
622     }
623   g_mutex_unlock (&gmem_profile_mutex);
624 }
625
626 static void
627 profile_print_locked (guint   *local_data,
628                       gboolean success)
629 {
630   gboolean need_header = TRUE;
631   guint i;
632
633   for (i = 0; i <= MEM_PROFILE_TABLE_SIZE; i++)
634     {
635       glong t_malloc = local_data[i + PROFILE_TABLE (1, 0, success)];
636       glong t_realloc = local_data[i + PROFILE_TABLE (1, 1, success)];
637       glong t_free = local_data[i + PROFILE_TABLE (0, 0, success)];
638       glong t_refree = local_data[i + PROFILE_TABLE (0, 1, success)];
639       
640       if (!t_malloc && !t_realloc && !t_free && !t_refree)
641         continue;
642       else if (need_header)
643         {
644           need_header = FALSE;
645           g_print (" blocks of | allocated  | freed      | allocated  | freed      | n_bytes   \n");
646           g_print ("  n_bytes  | n_times by | n_times by | n_times by | n_times by | remaining \n");
647           g_print ("           | malloc()   | free()     | realloc()  | realloc()  |           \n");
648           g_print ("===========|============|============|============|============|===========\n");
649         }
650       if (i < MEM_PROFILE_TABLE_SIZE)
651         g_print ("%10u | %10ld | %10ld | %10ld | %10ld |%+11ld\n",
652                  i, t_malloc, t_free, t_realloc, t_refree,
653                  (t_malloc - t_free + t_realloc - t_refree) * i);
654       else if (i >= MEM_PROFILE_TABLE_SIZE)
655         g_print ("   >%6u | %10ld | %10ld | %10ld | %10ld |        ***\n",
656                  i, t_malloc, t_free, t_realloc, t_refree);
657     }
658   if (need_header)
659     g_print (" --- none ---\n");
660 }
661
662 /**
663  * g_mem_profile:
664  * @void:
665  * 
666  * Outputs a summary of memory usage.
667  * 
668  * It outputs the frequency of allocations of different sizes,
669  * the total number of bytes which have been allocated,
670  * the total number of bytes which have been freed,
671  * and the difference between the previous two values, i.e. the number of bytes
672  * still in use.
673  * 
674  * Note that this function will not output anything unless you have
675  * previously installed the #glib_mem_profiler_table with g_mem_set_vtable().
676  */
677
678 void
679 g_mem_profile (void)
680 {
681   guint local_data[(MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])];
682   gsize local_allocs;
683   gsize local_zinit;
684   gsize local_frees;
685
686   g_mutex_lock (&gmem_profile_mutex);
687
688   local_allocs = profile_allocs;
689   local_zinit = profile_zinit;
690   local_frees = profile_frees;
691
692   if (!profile_data)
693     {
694       g_mutex_unlock (&gmem_profile_mutex);
695       return;
696     }
697
698   memcpy (local_data, profile_data, 
699           (MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0]));
700   
701   g_mutex_unlock (&gmem_profile_mutex);
702
703   g_print ("GLib Memory statistics (successful operations):\n");
704   profile_print_locked (local_data, TRUE);
705   g_print ("GLib Memory statistics (failing operations):\n");
706   profile_print_locked (local_data, FALSE);
707   g_print ("Total bytes: allocated=%"G_GSIZE_FORMAT", "
708            "zero-initialized=%"G_GSIZE_FORMAT" (%.2f%%), "
709            "freed=%"G_GSIZE_FORMAT" (%.2f%%), "
710            "remaining=%"G_GSIZE_FORMAT"\n",
711            local_allocs,
712            local_zinit,
713            ((gdouble) local_zinit) / local_allocs * 100.0,
714            local_frees,
715            ((gdouble) local_frees) / local_allocs * 100.0,
716            local_allocs - local_frees);
717 }
718
719 static gpointer
720 profiler_try_malloc (gsize n_bytes)
721 {
722   gsize *p;
723
724 #ifdef  G_ENABLE_DEBUG
725   if (g_trap_malloc_size == n_bytes)
726     G_BREAKPOINT ();
727 #endif  /* G_ENABLE_DEBUG */
728
729   p = standard_malloc (sizeof (gsize) * 2 + n_bytes);
730
731   if (p)
732     {
733       p[0] = 0;         /* free count */
734       p[1] = n_bytes;   /* length */
735       profiler_log (PROFILER_ALLOC, n_bytes, TRUE);
736       p += 2;
737     }
738   else
739     profiler_log (PROFILER_ALLOC, n_bytes, FALSE);
740   
741   return p;
742 }
743
744 static gpointer
745 profiler_malloc (gsize n_bytes)
746 {
747   gpointer mem = profiler_try_malloc (n_bytes);
748
749   if (!mem)
750     g_mem_profile ();
751
752   return mem;
753 }
754
755 static gpointer
756 profiler_calloc (gsize n_blocks,
757                  gsize n_block_bytes)
758 {
759   gsize l = n_blocks * n_block_bytes;
760   gsize *p;
761
762 #ifdef  G_ENABLE_DEBUG
763   if (g_trap_malloc_size == l)
764     G_BREAKPOINT ();
765 #endif  /* G_ENABLE_DEBUG */
766   
767   p = standard_calloc (1, sizeof (gsize) * 2 + l);
768
769   if (p)
770     {
771       p[0] = 0;         /* free count */
772       p[1] = l;         /* length */
773       profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, TRUE);
774       p += 2;
775     }
776   else
777     {
778       profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, FALSE);
779       g_mem_profile ();
780     }
781
782   return p;
783 }
784
785 static void
786 profiler_free (gpointer mem)
787 {
788   gsize *p = mem;
789
790   p -= 2;
791   if (p[0])     /* free count */
792     {
793       g_warning ("free(%p): memory has been freed %"G_GSIZE_FORMAT" times already",
794                  p + 2, p[0]);
795       profiler_log (PROFILER_FREE,
796                     p[1],       /* length */
797                     FALSE);
798     }
799   else
800     {
801 #ifdef  G_ENABLE_DEBUG
802       if (g_trap_free_size == p[1])
803         G_BREAKPOINT ();
804 #endif  /* G_ENABLE_DEBUG */
805
806       profiler_log (PROFILER_FREE,
807                     p[1],       /* length */
808                     TRUE);
809       memset (p + 2, 0xaa, p[1]);
810
811       /* for all those that miss standard_free (p); in this place, yes,
812        * we do leak all memory when profiling, and that is intentional
813        * to catch double frees. patch submissions are futile.
814        */
815     }
816   p[0] += 1;
817 }
818
819 static gpointer
820 profiler_try_realloc (gpointer mem,
821                       gsize    n_bytes)
822 {
823   gsize *p = mem;
824
825   p -= 2;
826
827 #ifdef  G_ENABLE_DEBUG
828   if (g_trap_realloc_size == n_bytes)
829     G_BREAKPOINT ();
830 #endif  /* G_ENABLE_DEBUG */
831   
832   if (mem && p[0])      /* free count */
833     {
834       g_warning ("realloc(%p, %"G_GSIZE_FORMAT"): "
835                  "memory has been freed %"G_GSIZE_FORMAT" times already",
836                  p + 2, (gsize) n_bytes, p[0]);
837       profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE);
838
839       return NULL;
840     }
841   else
842     {
843       p = standard_realloc (mem ? p : NULL, sizeof (gsize) * 2 + n_bytes);
844
845       if (p)
846         {
847           if (mem)
848             profiler_log (PROFILER_FREE | PROFILER_RELOC, p[1], TRUE);
849           p[0] = 0;
850           p[1] = n_bytes;
851           profiler_log (PROFILER_ALLOC | PROFILER_RELOC, p[1], TRUE);
852           p += 2;
853         }
854       else
855         profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE);
856
857       return p;
858     }
859 }
860
861 static gpointer
862 profiler_realloc (gpointer mem,
863                   gsize    n_bytes)
864 {
865   mem = profiler_try_realloc (mem, n_bytes);
866
867   if (!mem)
868     g_mem_profile ();
869
870   return mem;
871 }
872
873 static GMemVTable profiler_table = {
874   profiler_malloc,
875   profiler_realloc,
876   profiler_free,
877   profiler_calloc,
878   profiler_try_malloc,
879   profiler_try_realloc,
880 };
881 GMemVTable *glib_mem_profiler_table = &profiler_table;
882
883 #endif  /* !G_DISABLE_CHECKS */