[glib: 1/4] gobject: Assert that GObjects are at least as aligned as basic types




commit 0749643daaa818e78d68da27db5378f15eb31e0b
Author: Philip Withnall <withnall endlessm com>
Date:   Fri Dec 8 14:34:34 2017 +0000

    gobject: Assert that GObjects are at least as aligned as basic types
    
    See the reasoning in the patch for why we believe GObjects *are*
    (already) as aligned as the basic types.
    
    We want to make this guarantee so that it’s guaranteed to be safe for
    people to ignore -Wcast-align warnings for GObjects which contain basic
    types. This typically happens with gdouble on 32-bit ARM platforms.
    
    The checks are slightly complicated by the need to support GObjects with
    custom constructors. We should expect that a custom construction
    function will chain up to g_object_constructor (which calls
    g_type_create_instance() as normal), but it’s possible that someone has
    done something crazy and uses a custom allocator which doesn’t return
    with the same alignment as GSlice. Hand them a warning in that case. If
    that is true, the code which uses their custom-constructed GObject can
    presumably already deal with the alignment it gets given.
    
    Signed-off-by: Philip Withnall <withnall endlessm com>
    
    Helps: #1231

 gobject/gobject.c | 38 ++++++++++++++++++++++++++++++++++++++
 gobject/gobject.h |  4 ++++
 gobject/gtype.h   |  4 ++++
 3 files changed, 46 insertions(+)
---
diff --git a/gobject/gobject.c b/gobject/gobject.c
index ae89b7462..ac94454cd 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -24,6 +24,8 @@
 #include <string.h>
 #include <signal.h>
 
+#include "../glib/glib-private.h"
+
 #include "gobject.h"
 #include "gtype-private.h"
 #include "gvaluecollector.h"
@@ -1794,6 +1796,10 @@ g_object_get_type (void)
  * Similarly, #gfloat is promoted to #gdouble, so you must ensure that the value
  * you provide is a #gdouble, even for a property of type #gfloat.
  *
+ * Since GLib 2.72, all #GObjects are guaranteed to be aligned to at least the
+ * alignment of the largest basic GLib type (typically this is #guint64 or
+ * #gdouble).
+ *
  * Returns: (transfer full) (type GObject.Object): a new instance of
  *   @object_type
  */
@@ -1816,6 +1822,26 @@ g_object_new (GType         object_type,
   return object;
 }
 
+/* Check alignment. (See https://gitlab.gnome.org/GNOME/glib/-/issues/1231.)
+ * This should never fail, since g_type_create_instance() uses g_slice_alloc0().
+ * The GSlice allocator always aligns to the next power of 2 greater than the
+ * allocation size. The allocation size for a GObject is
+ *   sizeof(GTypeInstance) + sizeof(guint) + sizeof(GData*)
+ * which is 12B on 32-bit platforms, and larger on 64-bit systems. In both
+ * cases, that’s larger than the 8B needed for a guint64 or gdouble.
+ *
+ * If GSlice falls back to malloc(), it’s documented to return something
+ * suitably aligned for any basic type. */
+static inline gboolean
+g_object_is_aligned (GObject *object)
+{
+  return ((((guintptr) (void *) object) %
+             MAX (G_ALIGNOF (gdouble),
+                  MAX (G_ALIGNOF (guint64),
+                       MAX (G_ALIGNOF (gint),
+                            G_ALIGNOF (glong))))) == 0);
+}
+
 static gpointer
 g_object_new_with_custom_constructor (GObjectClass          *class,
                                       GObjectConstructParam *params,
@@ -1903,6 +1929,16 @@ g_object_new_with_custom_constructor (GObjectClass          *class,
       return NULL;
     }
 
+  if (!g_object_is_aligned (object))
+    {
+      g_critical ("Custom constructor for class %s returned a non-aligned "
+                  "GObject (which is invalid since GLib 2.72). Assuming any "
+                  "code using this object doesn’t require it to be aligned. "
+                  "Please fix your constructor to align to the largest GLib "
+                  "basic type (typically gdouble or guint64).",
+                  G_OBJECT_CLASS_NAME (class));
+    }
+
   /* g_object_init() will have marked the object as being in-construction.
    * Check if the returned object still is so marked, or if this is an
    * already-existing singleton (in which case we should not do 'constructed').
@@ -1969,6 +2005,8 @@ g_object_new_internal (GObjectClass          *class,
 
   object = (GObject *) g_type_create_instance (class->g_type_class.g_type);
 
+  g_assert (g_object_is_aligned (object));
+
   if (CLASS_HAS_PROPS (class))
     {
       GSList *node;
diff --git a/gobject/gobject.h b/gobject/gobject.h
index d74bebc7c..8bcb0cdbc 100644
--- a/gobject/gobject.h
+++ b/gobject/gobject.h
@@ -253,6 +253,10 @@ typedef void (*GWeakNotify)                (gpointer      data,
  * 
  * All the fields in the `GObject` structure are private to the implementation
  * and should never be accessed directly.
+ *
+ * Since GLib 2.72, all #GObjects are guaranteed to be aligned to at least the
+ * alignment of the largest basic GLib type (typically this is #guint64 or
+ * #gdouble).
  */
 struct  _GObject
 {
diff --git a/gobject/gtype.h b/gobject/gtype.h
index 874a7c00c..c6bccc010 100644
--- a/gobject/gtype.h
+++ b/gobject/gtype.h
@@ -1981,6 +1981,10 @@ guint     g_type_get_type_registration_serial (void);
  *   }
  * ]|
  *
+ * Since GLib 2.72, the returned `MyObjectPrivate` pointer is guaranteed to be
+ * aligned to at least the alignment of the largest basic GLib type (typically
+ * this is #guint64 or #gdouble).
+ *
  * Note that this macro can only be used together with the `G_DEFINE_TYPE_*`
  * macros, since it depends on variable names from those macros.
  *


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