[glib] Deprecate and drop support for memory vtables



commit 3be6ed60aa58095691bd697344765e715a327fc1
Author: Alexander Larsson <alexl redhat com>
Date:   Sat Jun 27 18:38:42 2015 +0200

    Deprecate and drop support for memory vtables
    
    The memory vtables no longer work, because glib contructors are called
    before main(), so there is no way to set it them before use. This stops using
    the vtable at all, and deprecates and stubs out the related functions.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=751592

 glib/gmem.c |  386 +++++------------------------------------------------------
 glib/gmem.h |    8 +-
 2 files changed, 34 insertions(+), 360 deletions(-)
---
diff --git a/glib/gmem.c b/glib/gmem.c
index dd031ba..c76ae17 100644
--- a/glib/gmem.c
+++ b/glib/gmem.c
@@ -40,9 +40,6 @@
 #include "gthread.h"
 #include "glib_trace.h"
 
-#define MEM_PROFILE_TABLE_SIZE 4096
-
-
 /* notes on macros:
  * having G_DISABLE_CHECKS defined disables use of glib_mem_profiler_table and
  * g_mem_profile().
@@ -74,7 +71,7 @@ static GMemVTable glib_mem_vtable = {
  * g_slice_free(), plain malloc() with free(), and (if you're using C++)
  * new with delete and new[] with delete[]. Otherwise bad things can happen,
  * since these allocators may use different memory pools (and new/delete call
- * constructors and destructors). See also g_mem_set_vtable().
+ * constructors and destructors).
  */
 
 /* --- functions --- */
@@ -94,7 +91,7 @@ g_malloc (gsize n_bytes)
     {
       gpointer mem;
 
-      mem = glib_mem_vtable.malloc (n_bytes);
+      mem = malloc (n_bytes);
       TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 0, 0));
       if (mem)
        return mem;
@@ -124,7 +121,7 @@ g_malloc0 (gsize n_bytes)
     {
       gpointer mem;
 
-      mem = glib_mem_vtable.calloc (1, n_bytes);
+      mem = calloc (1, n_bytes);
       TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 1, 0));
       if (mem)
        return mem;
@@ -159,7 +156,7 @@ g_realloc (gpointer mem,
 
   if (G_LIKELY (n_bytes))
     {
-      newmem = glib_mem_vtable.realloc (mem, n_bytes);
+      newmem = realloc (mem, n_bytes);
       TRACE (GLIB_MEM_REALLOC((void*) newmem, (void*)mem, (unsigned int) n_bytes, 0));
       if (newmem)
        return newmem;
@@ -169,7 +166,7 @@ g_realloc (gpointer mem,
     }
 
   if (mem)
-    glib_mem_vtable.free (mem);
+    free (mem);
 
   TRACE (GLIB_MEM_REALLOC((void*) NULL, (void*)mem, 0, 0));
 
@@ -189,7 +186,7 @@ void
 g_free (gpointer mem)
 {
   if (G_LIKELY (mem))
-    glib_mem_vtable.free (mem);
+    free (mem);
   TRACE(GLIB_MEM_FREE((void*) mem));
 }
 
@@ -241,7 +238,7 @@ g_try_malloc (gsize n_bytes)
   gpointer mem;
 
   if (G_LIKELY (n_bytes))
-    mem = glib_mem_vtable.try_malloc (n_bytes);
+    mem = malloc (n_bytes);
   else
     mem = NULL;
 
@@ -266,13 +263,10 @@ g_try_malloc0 (gsize n_bytes)
   gpointer mem;
 
   if (G_LIKELY (n_bytes))
-    mem = glib_mem_vtable.try_malloc (n_bytes);
+    mem = calloc (1, n_bytes);
   else
     mem = NULL;
 
-  if (mem)
-    memset (mem, 0, n_bytes);
-
   return mem;
 }
 
@@ -296,12 +290,12 @@ g_try_realloc (gpointer mem,
   gpointer newmem;
 
   if (G_LIKELY (n_bytes))
-    newmem = glib_mem_vtable.try_realloc (mem, n_bytes);
+    newmem = realloc (mem, n_bytes);
   else
     {
       newmem = NULL;
       if (mem)
-       glib_mem_vtable.free (mem);
+       free (mem);
     }
 
   TRACE (GLIB_MEM_REALLOC((void*) newmem, (void*)mem, (unsigned int) n_bytes, 1));
@@ -451,23 +445,6 @@ g_try_realloc_n (gpointer mem,
   return g_try_realloc (mem, n_blocks * n_block_bytes);
 }
 
-
-
-static gpointer
-fallback_calloc (gsize n_blocks,
-                gsize n_block_bytes)
-{
-  gsize l = n_blocks * n_block_bytes;
-  gpointer mem = glib_mem_vtable.malloc (l);
-
-  if (mem)
-    memset (mem, 0, l);
-
-  return mem;
-}
-
-static gboolean vtable_set = FALSE;
-
 /**
  * g_mem_is_system_malloc:
  * 
@@ -477,358 +454,53 @@ static gboolean vtable_set = FALSE;
  * This function is useful for avoiding an extra copy of allocated memory returned
  * by a non-GLib-based API.
  *
- * A different allocator can be set using g_mem_set_vtable().
- *
  * Returns: if %TRUE, malloc() and g_malloc() can be mixed.
+ *
+ * Deprecated: 2.46: GLib always uses the system malloc, so this function always
+ * returns %TRUE.
  **/
 gboolean
 g_mem_is_system_malloc (void)
 {
-  return !vtable_set;
+  return TRUE;
 }
 
 /**
  * g_mem_set_vtable:
  * @vtable: table of memory allocation routines.
  * 
- * Sets the #GMemVTable to use for memory allocation. You can use this
- * to provide custom memory allocation routines.
- *
- * The @vtable only needs to provide malloc(), realloc(), and free()
- * functions; GLib can provide default implementations of the others.
- * The malloc() and realloc() implementations should return %NULL on
- * failure, GLib will handle error-checking for you. @vtable is copied,
- * so need not persist after this function has been called.
+ * This function used to let you override the memory allocation function.
+ * However, its use was incompatible with the use of global constructors
+ * in GLib and GIO, because those use the GLib allocators before main is
+ * reached. Therefore this function is now deprecated and is just a stub.
  *
- * Note that this function must be called before using any other GLib
- * functions.
+ * Deprecated: 2.46: Use other memory profiling tools instead
  */
 void
 g_mem_set_vtable (GMemVTable *vtable)
 {
-  if (!vtable_set)
-    {
-      if (vtable->malloc && vtable->realloc && vtable->free)
-       {
-         glib_mem_vtable.malloc = vtable->malloc;
-         glib_mem_vtable.realloc = vtable->realloc;
-         glib_mem_vtable.free = vtable->free;
-         glib_mem_vtable.calloc = vtable->calloc ? vtable->calloc : fallback_calloc;
-         glib_mem_vtable.try_malloc = vtable->try_malloc ? vtable->try_malloc : glib_mem_vtable.malloc;
-         glib_mem_vtable.try_realloc = vtable->try_realloc ? vtable->try_realloc : glib_mem_vtable.realloc;
-         vtable_set = TRUE;
-       }
-      else
-       g_warning (G_STRLOC ": memory allocation vtable lacks one of malloc(), realloc() or free()");
-    }
-  else
-    g_warning (G_STRLOC ": memory allocation vtable can only be set once at startup");
+  g_warning (G_STRLOC ": custom memory allocation vtable not supported");
 }
 
 
-/* --- memory profiling and checking --- */
-#ifdef G_DISABLE_CHECKS
 /**
  * glib_mem_profiler_table:
- * 
- * A #GMemVTable containing profiling variants of the memory
- * allocation functions. Use them together with g_mem_profile()
- * in order to get information about the memory allocation pattern
- * of your program.
+ *
+ * Deprecated: 2.46: Use other memory profiling tools instead
  */
 GMemVTable *glib_mem_profiler_table = &glib_mem_vtable;
-void
-g_mem_profile (void)
-{
-}
-#else  /* !G_DISABLE_CHECKS */
-typedef enum {
-  PROFILER_FREE                = 0,
-  PROFILER_ALLOC       = 1,
-  PROFILER_RELOC       = 2,
-  PROFILER_ZINIT       = 4
-} ProfilerJob;
-static guint *profile_data = NULL;
-static gsize profile_allocs = 0;
-static gsize profile_zinit = 0;
-static gsize profile_frees = 0;
-static GMutex gmem_profile_mutex;
-
-#define        PROFILE_TABLE(f1,f2,f3)   ( ( ((f3) << 2) | ((f2) << 1) | (f1) ) * (MEM_PROFILE_TABLE_SIZE + 
1))
-
-static void
-profiler_log (ProfilerJob job,
-             gsize       n_bytes,
-             gboolean    success)
-{
-  g_mutex_lock (&gmem_profile_mutex);
-  if (!profile_data)
-    {
-      profile_data = calloc ((MEM_PROFILE_TABLE_SIZE + 1) * 8, 
-                             sizeof (profile_data[0]));
-      if (!profile_data)       /* memory system kiddin' me, eh? */
-       {
-         g_mutex_unlock (&gmem_profile_mutex);
-         return;
-       }
-    }
-
-  if (n_bytes < MEM_PROFILE_TABLE_SIZE)
-    profile_data[n_bytes + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0,
-                                          (job & PROFILER_RELOC) != 0,
-                                          success != 0)] += 1;
-  else
-    profile_data[MEM_PROFILE_TABLE_SIZE + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0,
-                                                         (job & PROFILER_RELOC) != 0,
-                                                         success != 0)] += 1;
-  if (success)
-    {
-      if (job & PROFILER_ALLOC)
-        {
-          profile_allocs += n_bytes;
-          if (job & PROFILER_ZINIT)
-            profile_zinit += n_bytes;
-        }
-      else
-        profile_frees += n_bytes;
-    }
-  g_mutex_unlock (&gmem_profile_mutex);
-}
-
-static void
-profile_print_locked (guint   *local_data,
-                     gboolean success)
-{
-  gboolean need_header = TRUE;
-  guint i;
-
-  for (i = 0; i <= MEM_PROFILE_TABLE_SIZE; i++)
-    {
-      glong t_malloc = local_data[i + PROFILE_TABLE (1, 0, success)];
-      glong t_realloc = local_data[i + PROFILE_TABLE (1, 1, success)];
-      glong t_free = local_data[i + PROFILE_TABLE (0, 0, success)];
-      glong t_refree = local_data[i + PROFILE_TABLE (0, 1, success)];
-      
-      if (!t_malloc && !t_realloc && !t_free && !t_refree)
-       continue;
-      else if (need_header)
-       {
-         need_header = FALSE;
-         g_print (" blocks of | allocated  | freed      | allocated  | freed      | n_bytes   \n");
-         g_print ("  n_bytes  | n_times by | n_times by | n_times by | n_times by | remaining \n");
-         g_print ("           | malloc()   | free()     | realloc()  | realloc()  |           \n");
-         g_print ("===========|============|============|============|============|===========\n");
-       }
-      if (i < MEM_PROFILE_TABLE_SIZE)
-       g_print ("%10u | %10ld | %10ld | %10ld | %10ld |%+11ld\n",
-                i, t_malloc, t_free, t_realloc, t_refree,
-                (t_malloc - t_free + t_realloc - t_refree) * i);
-      else if (i >= MEM_PROFILE_TABLE_SIZE)
-       g_print ("   >%6u | %10ld | %10ld | %10ld | %10ld |        ***\n",
-                i, t_malloc, t_free, t_realloc, t_refree);
-    }
-  if (need_header)
-    g_print (" --- none ---\n");
-}
 
 /**
  * g_mem_profile:
- * 
- * Outputs a summary of memory usage.
- * 
- * It outputs the frequency of allocations of different sizes,
- * the total number of bytes which have been allocated,
- * the total number of bytes which have been freed,
- * and the difference between the previous two values, i.e. the number of bytes
- * still in use.
- * 
- * Note that this function will not output anything unless you have
- * previously installed the #glib_mem_profiler_table with g_mem_set_vtable().
+ *
+ * GLib used to support some tools for memory profiling, but this
+ * no longer works. There are many other useful tools for memory
+ * profiling these days which can be used instead.
+ *
+ * Deprecated: 2.46: Use other memory profiling tools instead
  */
-
 void
 g_mem_profile (void)
 {
-  guint local_data[(MEM_PROFILE_TABLE_SIZE + 1) * 8];
-  gsize local_allocs;
-  gsize local_zinit;
-  gsize local_frees;
-
-  g_mutex_lock (&gmem_profile_mutex);
-
-  local_allocs = profile_allocs;
-  local_zinit = profile_zinit;
-  local_frees = profile_frees;
-
-  if (!profile_data)
-    {
-      g_mutex_unlock (&gmem_profile_mutex);
-      return;
-    }
-
-  memcpy (local_data, profile_data, 
-         (MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0]));
-  
-  g_mutex_unlock (&gmem_profile_mutex);
-
-  g_print ("GLib Memory statistics (successful operations):\n");
-  profile_print_locked (local_data, TRUE);
-  g_print ("GLib Memory statistics (failing operations):\n");
-  profile_print_locked (local_data, FALSE);
-  g_print ("Total bytes: allocated=%"G_GSIZE_FORMAT", "
-           "zero-initialized=%"G_GSIZE_FORMAT" (%.2f%%), "
-           "freed=%"G_GSIZE_FORMAT" (%.2f%%), "
-           "remaining=%"G_GSIZE_FORMAT"\n",
-          local_allocs,
-          local_zinit,
-          ((gdouble) local_zinit) / local_allocs * 100.0,
-          local_frees,
-          ((gdouble) local_frees) / local_allocs * 100.0,
-          local_allocs - local_frees);
+  g_warning (G_STRLOC ": memory profiling not supported");
 }
-
-static gpointer
-profiler_try_malloc (gsize n_bytes)
-{
-  gsize *p;
-
-  p = malloc (sizeof (gsize) * 2 + n_bytes);
-
-  if (p)
-    {
-      p[0] = 0;                /* free count */
-      p[1] = n_bytes;  /* length */
-      profiler_log (PROFILER_ALLOC, n_bytes, TRUE);
-      p += 2;
-    }
-  else
-    profiler_log (PROFILER_ALLOC, n_bytes, FALSE);
-  
-  return p;
-}
-
-static gpointer
-profiler_malloc (gsize n_bytes)
-{
-  gpointer mem = profiler_try_malloc (n_bytes);
-
-  if (!mem)
-    g_mem_profile ();
-
-  return mem;
-}
-
-static gpointer
-profiler_calloc (gsize n_blocks,
-                gsize n_block_bytes)
-{
-  gsize l = n_blocks * n_block_bytes;
-  gsize *p;
-
-  p = calloc (1, sizeof (gsize) * 2 + l);
-
-  if (p)
-    {
-      p[0] = 0;                /* free count */
-      p[1] = l;                /* length */
-      profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, TRUE);
-      p += 2;
-    }
-  else
-    {
-      profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, FALSE);
-      g_mem_profile ();
-    }
-
-  return p;
-}
-
-static void
-profiler_free (gpointer mem)
-{
-  gsize *p = mem;
-
-  p -= 2;
-  if (p[0])    /* free count */
-    {
-      g_warning ("free(%p): memory has been freed %"G_GSIZE_FORMAT" times already",
-                 p + 2, p[0]);
-      profiler_log (PROFILER_FREE,
-                   p[1],       /* length */
-                   FALSE);
-    }
-  else
-    {
-      profiler_log (PROFILER_FREE,
-                   p[1],       /* length */
-                   TRUE);
-      memset (p + 2, 0xaa, p[1]);
-
-      /* for all those that miss free (p); in this place, yes,
-       * we do leak all memory when profiling, and that is intentional
-       * to catch double frees. patch submissions are futile.
-       */
-    }
-  p[0] += 1;
-}
-
-static gpointer
-profiler_try_realloc (gpointer mem,
-                     gsize    n_bytes)
-{
-  gsize *p = mem;
-
-  p -= 2;
-  
-  if (mem && p[0])     /* free count */
-    {
-      g_warning ("realloc(%p, %"G_GSIZE_FORMAT"): "
-                 "memory has been freed %"G_GSIZE_FORMAT" times already",
-                 p + 2, (gsize) n_bytes, p[0]);
-      profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE);
-
-      return NULL;
-    }
-  else
-    {
-      p = realloc (mem ? p : NULL, sizeof (gsize) * 2 + n_bytes);
-
-      if (p)
-       {
-         if (mem)
-           profiler_log (PROFILER_FREE | PROFILER_RELOC, p[1], TRUE);
-         p[0] = 0;
-         p[1] = n_bytes;
-         profiler_log (PROFILER_ALLOC | PROFILER_RELOC, p[1], TRUE);
-         p += 2;
-       }
-      else
-       profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE);
-
-      return p;
-    }
-}
-
-static gpointer
-profiler_realloc (gpointer mem,
-                 gsize    n_bytes)
-{
-  mem = profiler_try_realloc (mem, n_bytes);
-
-  if (!mem)
-    g_mem_profile ();
-
-  return mem;
-}
-
-static GMemVTable profiler_table = {
-  profiler_malloc,
-  profiler_realloc,
-  profiler_free,
-  profiler_calloc,
-  profiler_try_malloc,
-  profiler_try_realloc,
-};
-GMemVTable *glib_mem_profiler_table = &profiler_table;
-
-#endif /* !G_DISABLE_CHECKS */
diff --git a/glib/gmem.h b/glib/gmem.h
index 10fee07..031271d 100644
--- a/glib/gmem.h
+++ b/glib/gmem.h
@@ -45,6 +45,8 @@ G_BEGIN_DECLS
  * A set of functions used to perform memory allocation. The same #GMemVTable must
  * be used for all allocations in the same program; a call to g_mem_set_vtable(),
  * if it exists, should be prior to any use of GLib.
+ *
+ * This functions related to this has been deprecated in 2.46, and no longer work.
  */
 typedef struct _GMemVTable GMemVTable;
 
@@ -351,9 +353,9 @@ struct _GMemVTable {
   gpointer (*try_realloc) (gpointer mem,
                           gsize    n_bytes);
 };
-GLIB_AVAILABLE_IN_ALL
+GLIB_DEPRECATED_IN_2_46
 void    g_mem_set_vtable (GMemVTable   *vtable);
-GLIB_AVAILABLE_IN_ALL
+GLIB_DEPRECATED_IN_2_46
 gboolean g_mem_is_system_malloc (void);
 
 GLIB_VAR gboolean g_mem_gc_friendly;
@@ -361,7 +363,7 @@ GLIB_VAR gboolean g_mem_gc_friendly;
 /* Memory profiler and checker, has to be enabled via g_mem_set_vtable()
  */
 GLIB_VAR GMemVTable    *glib_mem_profiler_table;
-GLIB_AVAILABLE_IN_ALL
+GLIB_DEPRECATED_IN_2_46
 void   g_mem_profile   (void);
 
 G_END_DECLS


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]