summaryrefslogtreecommitdiff
path: root/gobject
diff options
context:
space:
mode:
authorPhilip Withnall <withnall@endlessm.com>2017-12-08 14:34:34 +0000
committerPhilip Withnall <pwithnall@endlessos.org>2021-11-17 11:56:20 +0000
commit0749643daaa818e78d68da27db5378f15eb31e0b (patch)
treef700be5962f88ded19a48f2af7fd5fe8cf038412 /gobject
parente7e2949f31b472aac87dac5fa04740cd22d5d462 (diff)
downloadglib-0749643daaa818e78d68da27db5378f15eb31e0b.tar.gz
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
Diffstat (limited to 'gobject')
-rw-r--r--gobject/gobject.c38
-rw-r--r--gobject/gobject.h4
-rw-r--r--gobject/gtype.h4
3 files changed, 46 insertions, 0 deletions
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.
*