[glib] g_object_new: check for NULL from _constructor()



commit 7d61da0c078fcc10fada292811401b127e330555
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Apr 26 11:27:51 2013 -0400

    g_object_new: check for NULL from _constructor()
    
    There is some code in the wild (like in gnome-session) that does this
    from its custom _constructor() implementation:
    
    {
      GObject *obj;
    
      obj = ((chain up));
    
      if (!object_is_viable (obj))
        {
          g_object_unref (obj);
          return NULL;
        }
      else
        return obj;
    }
    
    This has never been a valid use of GObject and this code has always
    caused memory to be leaked[1] by growing the construction_objects list.
    The ability to legitimately return NULL from a constructor was exactly
    the reason that we created GInitable, in fact.
    
    That doesn't change the fact that the g_object_new() rewrite will crash
    in this case, so instead of doing that, let's emit a critical and avoid
    the crash.  This will allow people to upgrade their GLib without also
    upgrading their gnome-session.  Meanwhile, people can fix their broken
    code.
    
    [1] not in the strictest sense of the word, because it's still reachable

 gobject/gobject.c |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)
---
diff --git a/gobject/gobject.c b/gobject/gobject.c
index 543fc7d..38bbcca 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -1661,6 +1661,18 @@ g_object_new_with_custom_constructor (GObjectClass          *class,
     g_value_unset (&cvalues[cvals_used]);
   g_free (cvalues);
 
+  /* There is code in the wild that relies on being able to return NULL
+   * from its custom constructor.  This was never a supported operation
+   * and will leak memory, but since the code is already out there...
+   */
+  if (object == NULL)
+    {
+      g_critical ("Custom constructor for class %s returned NULL (which is invalid).  Unable to remove 
object "
+                  "from construction_objects list, so memory was probably just leaked.  Please use GInitable 
"
+                  "instead.", G_OBJECT_CLASS_NAME (class));
+      return NULL;
+    }
+
   /* g_object_init() will have added us to the construction_objects
    * list.  Check if we're in it (and remove us) in order to find
    * out if we were newly-constructed or this is an already-existing


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