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