g-i uses wrong offsets if a struct contains a nested struct (not a struct *)
Submitted by Simon McVittie
Link to original bug (#710665)
Description
This is with Debian's gobject-introspection 1.36.0-2+b1.
When I scanned the structs below and implemented the dup_parameters_array() vfunc, pygi and gjs wrongly placed the pointer in the identify_account() field - that's 56 bytes too early. That error would be consistent with g-i thinking the TpDBusPropertiesMixinClass (64 bytes) was a TpDBusPropertiesMixinClass* (8 bytes) when it calculated the offsets of the vfuncs.
Faulty structs:
typedef struct _TpDBusPropertiesMixinClass TpDBusPropertiesMixinClass;
struct _TpDBusPropertiesMixinClass {
TpDBusPropertiesMixinIfaceImpl *interfaces;
/*<private>*/
gpointer _1;
gpointer _2;
gpointer _3;
gpointer _4;
gpointer _5;
gpointer _6;
gpointer _7;
};
struct _TpBaseProtocolClass
{
GObjectClass parent_class;
TpDBusPropertiesMixinClass dbus_properties_class;
gboolean is_stub;
const TpCMParamSpec *(*get_parameters) (TpBaseProtocol *self);
TpBaseConnection *(*new_connection) (TpBaseProtocol *self,
GHashTable *asv,
GError **error);
gchar *(*normalize_contact) (TpBaseProtocol *self,
const gchar *contact,
GError **error);
gchar *(*identify_account) (TpBaseProtocol *self,
GHashTable *asv,
GError **error);
/*<private>*/
GStrv (*_TP_SEAL (get_interfaces)) (TpBaseProtocol *self);
/*<public>*/
void (*get_connection_details) (TpBaseProtocol *self,
GStrv *connection_interfaces,
GType **channel_manager_types,
gchar **icon_name,
gchar **english_name,
gchar **vcard_field);
const TpPresenceStatusSpec * (*get_statuses) (TpBaseProtocol *self);
void (*get_avatar_details) (TpBaseProtocol *self,
GStrv *supported_mime_types,
guint *min_height,
guint *min_width,
guint *rec_height,
guint *rec_width,
guint *max_height,
guint *max_width,
guint *max_bytes);
GStrv (*dup_authentication_types) (TpBaseProtocol *self);
GPtrArray * (*get_interfaces_array) (TpBaseProtocol *self);
GPtrArray *(*dup_parameters_array) (TpBaseProtocol *self);
/*<private>*/
GCallback padding[3];
TpBaseProtocolClassPrivate *priv;
};
Workaround:
#ifndef __GI_SCANNER__
#ifndef __GTK_DOC_IGNORE__
/* See below. If this assertion fails on your platform, you'll have to
* do something clever. */
G_STATIC_ASSERT (sizeof (gpointer[8]) == sizeof (TpDBusPropertiesMixinClass));
#endif
#endif
struct _TpBaseProtocolClass
{
GObjectClass parent_class;
#ifdef __GI_SCANNER__
#ifndef __GTK_DOC_IGNORE__
/* g-i gets confused and thinks TpDBusPropertiesMixinClass is only
* one pointer long (as if it was a TpDBusPropertiesMixinClass *),
* resulting in everything after this point being off-by-56 on x86-64.
* Trick it into choosing the right offset - it does understand
* arrays, so we can use one of those. */
gpointer dbus_properties_class[8];
#endif
#else
TpDBusPropertiesMixinClass dbus_properties_class;
#endif
...
Edited by Philip Chimento