From d0e03f0930df990ef0624218799368cb47238df5 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Wed, 14 Dec 2022 23:55:19 +0000 Subject: [PATCH] GType: introduce GTYPE_TO_POINTER/GPOINTER_TO_TYPE On CHERI-enabled systems we use uintptr_t as the underlying storage for GType and therefore casting to gsize strips the upper bits from a pointer. Fix this by casting via uintptr_t instead and introduce a new set of macros to convert between GType and pointers. --- docs/reference/gobject/gobject-sections.txt | 2 ++ gio/gdbus-2.0/codegen/codegen.py | 4 ++-- glib/docs.c | 14 ++++++++++++++ gobject/gclosure.c | 2 +- gobject/gparam.c | 4 ++-- gobject/gparamspecs.c | 12 ++++++------ gobject/gtype.c | 6 +++--- gobject/gtype.h | 21 +++++++++++++++++++++ gobject/gvaluetypes.c | 4 ++-- 9 files changed, 53 insertions(+), 16 deletions(-) diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt index 8b0d33010..cf06cf183 100644 --- a/docs/reference/gobject/gobject-sections.txt +++ b/docs/reference/gobject/gobject-sections.txt @@ -48,6 +48,8 @@ G_TYPE_CHECK_CLASS_TYPE G_TYPE_CHECK_VALUE G_TYPE_CHECK_VALUE_TYPE G_TYPE_FLAG_RESERVED_ID_BIT +GPOINTER_TO_TYPE +GTYPE_TO_POINTER g_type_init GTypeDebugFlags g_type_init_with_debug_flags diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py index 393328152..9bdcf183e 100644 --- a/gio/gdbus-2.0/codegen/codegen.py +++ b/gio/gdbus-2.0/codegen/codegen.py @@ -5160,12 +5160,12 @@ class CodeGenerator: ) for i in self.ifaces: self.outfile.write( - ' g_hash_table_insert (lookup_hash, (gpointer) "%s", GSIZE_TO_POINTER (%sTYPE_%s_PROXY));\n' + ' g_hash_table_insert (lookup_hash, (gpointer) "%s", (gpointer) (guintptr) (%sTYPE_%s_PROXY));\n' % (i.name, i.ns_upper, i.name_upper) ) self.outfile.write(" g_once_init_leave (&once_init_value, 1);\n" " }\n") self.outfile.write( - " ret = (GType) GPOINTER_TO_SIZE (g_hash_table_lookup (lookup_hash, interface_name));\n" + " ret = (GType) (guintptr) (g_hash_table_lookup (lookup_hash, interface_name));\n" " if (ret == (GType) 0)\n" " ret = G_TYPE_DBUS_PROXY;\n" ) diff --git a/glib/docs.c b/glib/docs.c index cbfb31b42..ca66d7eeb 100644 --- a/glib/docs.c +++ b/glib/docs.c @@ -1108,6 +1108,12 @@ * @s: #gsize to stuff into the pointer * * Stuffs a #gsize into a pointer type. + * + * Remember, you may not store pointers in integers. This is not portable + * in any way, shape or form. These macros only allow storing integers in + * pointers, and preserve all bits of a pointer (e.g. on CHERI systems). + * The only types that can store pointers as well as integers are #guintptr + * and #gintptr. */ /** @@ -1116,6 +1122,14 @@ * * Extracts a #gsize from a pointer. The #gsize must have * been stored in the pointer with GSIZE_TO_POINTER(). + * + * Remember, you may not store pointers in integers. This is not portable + * in any way, shape or form. These macros only allow storing integers in + * pointers, and preserve all bits of a pointer (e.g. on CHERI systems). + * The only types that can store pointers as well as integers are #guintptr + * and #gintptr. + * + * See also GPOINTER_TO_TYPE() for #gsize. */ /* Byte order {{{1 */ diff --git a/gobject/gclosure.c b/gobject/gclosure.c index d9b2fbfa4..af219c268 100644 --- a/gobject/gclosure.c +++ b/gobject/gclosure.c @@ -1175,7 +1175,7 @@ g_signal_type_cclosure_new (GType itype, g_return_val_if_fail (G_TYPE_IS_CLASSED (itype) || G_TYPE_IS_INTERFACE (itype), NULL); g_return_val_if_fail (struct_offset >= sizeof (GTypeClass), NULL); - closure = g_closure_new_simple (sizeof (GClosure), (gpointer) itype); + closure = g_closure_new_simple (sizeof (GClosure), GTYPE_TO_POINTER (itype)); if (G_TYPE_IS_INTERFACE (itype)) { g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_iface_meta_marshal); diff --git a/gobject/gparam.c b/gobject/gparam.c index 33d449c34..311f8c984 100644 --- a/gobject/gparam.c +++ b/gobject/gparam.c @@ -1234,7 +1234,7 @@ g_param_spec_pool_list_owned (GParamSpecPool *pool, g_mutex_lock (&pool->mutex); data[0] = NULL; - data[1] = (gpointer) owner_type; + data[1] = GTYPE_TO_POINTER (owner_type); g_hash_table_foreach (pool->hash_table, pool_list, &data); g_mutex_unlock (&pool->mutex); @@ -1373,7 +1373,7 @@ g_param_spec_pool_list (GParamSpecPool *pool, d = g_type_depth (owner_type); slists = g_new0 (GSList*, d); data[0] = slists; - data[1] = (gpointer) owner_type; + data[1] = GTYPE_TO_POINTER (owner_type); data[2] = pool->hash_table; data[3] = &n_pspecs; diff --git a/gobject/gparamspecs.c b/gobject/gparamspecs.c index 5db328155..cf50df74f 100644 --- a/gobject/gparamspecs.c +++ b/gobject/gparamspecs.c @@ -1222,7 +1222,7 @@ param_gtype_set_default (GParamSpec *pspec, { GParamSpecGType *tspec = G_PARAM_SPEC_GTYPE (pspec); - value->data[0].v_pointer = GSIZE_TO_POINTER (tspec->is_a_type); + value->data[0].v_pointer = GTYPE_TO_POINTER (tspec->is_a_type); } static gboolean @@ -1230,7 +1230,7 @@ param_gtype_is_valid (GParamSpec *pspec, const GValue *value) { GParamSpecGType *tspec = G_PARAM_SPEC_GTYPE (pspec); - GType gtype = GPOINTER_TO_SIZE (value->data[0].v_pointer); + GType gtype = GPOINTER_TO_TYPE (value->data[0].v_pointer); return tspec->is_a_type == G_TYPE_NONE || g_type_is_a (gtype, tspec->is_a_type); @@ -1241,12 +1241,12 @@ param_gtype_validate (GParamSpec *pspec, GValue *value) { GParamSpecGType *tspec = G_PARAM_SPEC_GTYPE (pspec); - GType gtype = GPOINTER_TO_SIZE (value->data[0].v_pointer); + GType gtype = GPOINTER_TO_TYPE (value->data[0].v_pointer); guint changed = 0; if (tspec->is_a_type != G_TYPE_NONE && !g_type_is_a (gtype, tspec->is_a_type)) { - value->data[0].v_pointer = GSIZE_TO_POINTER (tspec->is_a_type); + value->data[0].v_pointer = GTYPE_TO_POINTER (tspec->is_a_type); changed++; } @@ -1258,8 +1258,8 @@ param_gtype_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2) { - GType p1 = GPOINTER_TO_SIZE (value1->data[0].v_pointer); - GType p2 = GPOINTER_TO_SIZE (value2->data[0].v_pointer); + GType p1 = GPOINTER_TO_TYPE (value1->data[0].v_pointer); + GType p2 = GPOINTER_TO_TYPE (value2->data[0].v_pointer); /* not much to compare here, try to at least provide stable lesser/greater result */ diff --git a/gobject/gtype.c b/gobject/gtype.c index ee936b544..17a950780 100644 --- a/gobject/gtype.c +++ b/gobject/gtype.c @@ -422,7 +422,7 @@ type_node_any_new_W (TypeNode *pnode, #endif } else - type = (GType) node; + type = GPOINTER_TO_TYPE (node); g_assert ((type & TYPE_ID_MASK) == 0); @@ -497,7 +497,7 @@ type_node_any_new_W (TypeNode *pnode, node->global_gdata = NULL; g_hash_table_insert (static_type_nodes_ht, (gpointer) g_quark_to_string (node->qname), - (gpointer) type); + GTYPE_TO_POINTER (type)); g_atomic_int_inc ((gint *)&type_registration_serial); @@ -3444,7 +3444,7 @@ g_type_from_name (const gchar *name) g_return_val_if_fail (name != NULL, 0); G_READ_LOCK (&type_rw_lock); - type = (GType) g_hash_table_lookup (static_type_nodes_ht, name); + type = GPOINTER_TO_TYPE (g_hash_table_lookup (static_type_nodes_ht, name)); G_READ_UNLOCK (&type_rw_lock); return type; diff --git a/gobject/gtype.h b/gobject/gtype.h index 2d067925c..a16da4593 100644 --- a/gobject/gtype.h +++ b/gobject/gtype.h @@ -2710,6 +2710,27 @@ const gchar * g_type_name_from_class (GTypeClass *g_class); */ #define G_TYPE_FLAG_RESERVED_ID_BIT ((GType) (1 << 0)) +/** + * GPOINTER_TO_TYPE: + * @p: The pointer to convert to a #GType + * + * This macro should be used instead of GPOINTER_TO_SIZE() to ensure + * portability since #GType is not guaranteed to be the same as #gsize. + * + * Since: 2.80 + */ +#define GPOINTER_TO_TYPE(p) ((GType) (guintptr) (p)) GOBJECT_AVAILABLE_MACRO_IN_2_80 +/** + * GTYPE_TO_POINTER: + * @t: The #GType to convert to a pointer + * + * This macro should be used instead of GSIZE_TO_POINTER() to ensure + * portability since #GType is not guaranteed to be the same as #gsize. + * + * Since: 2.80 + */ +#define GTYPE_TO_POINTER(t) ((gpointer) (guintptr) (t)) GOBJECT_AVAILABLE_MACRO_IN_2_80 + G_END_DECLS #endif /* __G_TYPE_H__ */ diff --git a/gobject/gvaluetypes.c b/gobject/gvaluetypes.c index f49058486..6ffa7fd8b 100644 --- a/gobject/gvaluetypes.c +++ b/gobject/gvaluetypes.c @@ -1208,7 +1208,7 @@ g_value_set_gtype (GValue *value, { g_return_if_fail (G_VALUE_HOLDS_GTYPE (value)); - value->data[0].v_pointer = GSIZE_TO_POINTER (v_gtype); + value->data[0].v_pointer = GTYPE_TO_POINTER (v_gtype); } @@ -1227,7 +1227,7 @@ g_value_get_gtype (const GValue *value) { g_return_val_if_fail (G_VALUE_HOLDS_GTYPE (value), 0); - return GPOINTER_TO_SIZE (value->data[0].v_pointer); + return GPOINTER_TO_TYPE (value->data[0].v_pointer); } /**