[gobject-introspection] repository: Fix conversion of FFI values on big-endian architectures



commit bf71aba06ccbd3ae4b49133724389cf76108f6d9
Author: Michel DÃnzer <michel daenzer net>
Date:   Thu Feb 16 11:25:55 2012 -0500

    repository: Fix conversion of FFI values on big-endian architectures
    
    Adapted from the fixes for (see bug 665152). It makes sure values are
    properly converted between glib and FFI, which is critical for big
    endian architectures.
    
    Patch adjusted to use GIArgument instead of custom union types
    by Colin Walters <walters verbum org>
    
    https://bugzilla.gnome.org/show_bug.cgi?id=668902

 girepository/gicallableinfo.c |  103 ++++++++++++++++++++++++++++-
 girepository/ginvoke.c        |  142 ++++++++++++++++++++++++++++++-----------
 2 files changed, 203 insertions(+), 42 deletions(-)
---
diff --git a/girepository/gicallableinfo.c b/girepository/gicallableinfo.c
index 28043fa..fec77b8 100644
--- a/girepository/gicallableinfo.c
+++ b/girepository/gicallableinfo.c
@@ -360,6 +360,79 @@ g_callable_info_iterate_return_attributes (GICallableInfo  *info,
   return TRUE;
 }
 
+/* Extract the correct bits from an ffi_arg return value into
+ * GIArgument: https://bugzilla.gnome.org/show_bug.cgi?id=665152
+ *
+ * Also see the ffi_call man page - the storage requirements for return
+ * values are "special".
+ */
+typedef GIArgument GIFFIReturnValue;
+
+static void
+set_gargument_from_ffi_return_value (GITypeInfo                  *return_info,
+                                     GIArgument                  *arg,
+                                     GIFFIReturnValue            *ffi_value)
+{
+    switch (g_type_info_get_tag (return_info)) {
+    case GI_TYPE_TAG_INT8:
+        arg->v_int8 = (gint8) ffi_value->v_long;
+        break;
+    case GI_TYPE_TAG_UINT8:
+        arg->v_uint8 = (guint8) ffi_value->v_ulong;
+        break;
+    case GI_TYPE_TAG_INT16:
+        arg->v_int16 = (gint16) ffi_value->v_long;
+        break;
+    case GI_TYPE_TAG_UINT16:
+        arg->v_uint16 = (guint16) ffi_value->v_ulong;
+        break;
+    case GI_TYPE_TAG_INT32:
+        arg->v_int32 = (gint32) ffi_value->v_long;
+        break;
+    case GI_TYPE_TAG_UINT32:
+    case GI_TYPE_TAG_BOOLEAN:
+    case GI_TYPE_TAG_UNICHAR:
+        arg->v_uint32 = (guint32) ffi_value->v_ulong;
+        break;
+    case GI_TYPE_TAG_INT64:
+        arg->v_int64 = (gint64) ffi_value->v_int64;
+        break;
+    case GI_TYPE_TAG_UINT64:
+        arg->v_uint64 = (guint64) ffi_value->v_uint64;
+        break;
+    case GI_TYPE_TAG_FLOAT:
+        arg->v_float = ffi_value->v_float;
+        break;
+    case GI_TYPE_TAG_DOUBLE:
+        arg->v_double = ffi_value->v_double;
+        break;
+    case GI_TYPE_TAG_INTERFACE:
+        {
+            GIBaseInfo* interface_info;
+            GIInfoType interface_type;
+
+            interface_info = g_type_info_get_interface(return_info);
+            interface_type = g_base_info_get_type(interface_info);
+
+            switch(interface_type) {
+            case GI_INFO_TYPE_ENUM:
+            case GI_INFO_TYPE_FLAGS:
+                arg->v_int32 = (gint32) ffi_value->v_long;
+                break;
+            default:
+                arg->v_pointer = (gpointer) ffi_value->v_ulong;
+                break;
+            }
+
+            g_base_info_unref(interface_info);
+        }
+        break;
+    default:
+        arg->v_pointer = (gpointer) ffi_value->v_ulong;
+        break;
+    }
+}
+
 gboolean
 _g_callable_info_invoke (GIFunctionInfo *info,
                          gpointer          function,
@@ -376,16 +449,20 @@ _g_callable_info_invoke (GIFunctionInfo *info,
   ffi_type *rtype;
   ffi_type **atypes;
   GITypeInfo *tinfo;
+  GITypeInfo *rinfo;
+  GITypeTag rtag;
   GIArgInfo *ainfo;
   gint n_args, n_invoke_args, in_pos, out_pos, i;
   gpointer *args;
   gboolean success = FALSE;
   GError *local_error = NULL;
   gpointer error_address = &local_error;
+  GIFFIReturnValue ffi_return_value;
+  gpointer return_value_p; /* Will point inside the union return_value */
 
-  tinfo = g_callable_info_get_return_type ((GICallableInfo *)info);
-  rtype = g_type_info_get_ffi_type (tinfo);
-  g_base_info_unref ((GIBaseInfo *)tinfo);
+  rinfo = g_callable_info_get_return_type ((GICallableInfo *)info);
+  rtype = g_type_info_get_ffi_type (rinfo);
+  rtag = g_type_info_get_tag(rinfo);
 
   in_pos = 0;
   out_pos = 0;
@@ -516,7 +593,23 @@ _g_callable_info_invoke (GIFunctionInfo *info,
     goto out;
 
   g_return_val_if_fail (return_value, FALSE);
-  ffi_call (&cif, function, return_value, args);
+  /* See comment for GIFFIReturnValue above */
+  switch (rtag)
+    {
+    case GI_TYPE_TAG_FLOAT:
+      return_value_p = &ffi_return_value.v_float;
+      break;
+    case GI_TYPE_TAG_DOUBLE:
+      return_value_p = &ffi_return_value.v_double;
+      break;
+    case GI_TYPE_TAG_INT64:
+    case GI_TYPE_TAG_UINT64:
+      return_value_p = &ffi_return_value.v_uint64;
+      break;
+    default:
+      return_value_p = &ffi_return_value.v_long;
+    }
+  ffi_call (&cif, function, return_value_p, args);
 
   if (local_error)
     {
@@ -525,8 +618,10 @@ _g_callable_info_invoke (GIFunctionInfo *info,
     }
   else
     {
+      set_gargument_from_ffi_return_value(rinfo, return_value, &ffi_return_value);
       success = TRUE;
     }
  out:
+  g_base_info_unref ((GIBaseInfo *)rinfo);
   return success;
 }
diff --git a/girepository/ginvoke.c b/girepository/ginvoke.c
index 84e1e74..581956a 100644
--- a/girepository/ginvoke.c
+++ b/girepository/ginvoke.c
@@ -88,57 +88,121 @@ value_to_ffi_type (const GValue *gvalue, gpointer *value)
   return rettype;
 }
 
+/* See comment aboe set_gargument_from_ffi_return_value() */
+static ffi_type *
+g_value_to_ffi_return_type (const GValue *gvalue,
+			    const GIArgument *ffi_value,
+			    gpointer *value)
+{
+  ffi_type *rettype = NULL;
+  GType type = g_type_fundamental (G_VALUE_TYPE (gvalue));
+  g_assert (type != G_TYPE_INVALID);
+
+  *value = (gpointer)&(ffi_value->v_long);
+
+  switch (type) {
+  case G_TYPE_CHAR:
+    rettype = &ffi_type_sint8;
+    break;
+  case G_TYPE_UCHAR:
+    rettype = &ffi_type_uint8;
+    break;
+  case G_TYPE_BOOLEAN:
+  case G_TYPE_INT:
+    rettype = &ffi_type_sint;
+    break;
+  case G_TYPE_UINT:
+    rettype = &ffi_type_uint;
+    break;
+  case G_TYPE_STRING:
+  case G_TYPE_OBJECT:
+  case G_TYPE_BOXED:
+  case G_TYPE_POINTER:
+    rettype = &ffi_type_pointer;
+    break;
+  case G_TYPE_FLOAT:
+    rettype = &ffi_type_float;
+    *value = (gpointer)&(ffi_value->v_float);
+    break;
+  case G_TYPE_DOUBLE:
+    rettype = &ffi_type_double;
+    *value = (gpointer)&(ffi_value->v_double);
+    break;
+  case G_TYPE_LONG:
+    rettype = &ffi_type_slong;
+    break;
+  case G_TYPE_ULONG:
+    rettype = &ffi_type_ulong;
+    break;
+  case G_TYPE_INT64:
+    rettype = &ffi_type_sint64;
+    *value = (gpointer)&(ffi_value->v_int64);
+    break;
+  case G_TYPE_UINT64:
+    rettype = &ffi_type_uint64;
+    *value = (gpointer)&(ffi_value->v_uint64);
+    break;
+  default:
+    rettype = &ffi_type_pointer;
+    *value = NULL;
+    g_warning ("Unsupported fundamental type: %s", g_type_name (type));
+    break;
+  }
+  return rettype;
+}
+
 static void
-value_from_ffi_type (GValue *gvalue, gpointer *value)
+g_value_from_ffi_value (GValue           *gvalue,
+                        const GIArgument *value)
 {
-  switch (g_type_fundamental (G_VALUE_TYPE (gvalue)))
-    {
-    case G_TYPE_INT:
-      g_value_set_int (gvalue, *(gint*)value);
+  switch (g_type_fundamental (G_VALUE_TYPE (gvalue))) {
+  case G_TYPE_INT:
+      g_value_set_int (gvalue, (gint)value->v_long);
       break;
-    case G_TYPE_FLOAT:
-      g_value_set_float (gvalue, *(gfloat*)value);
+  case G_TYPE_FLOAT:
+      g_value_set_float (gvalue, (gfloat)value->v_float);
       break;
-    case G_TYPE_DOUBLE:
-      g_value_set_double (gvalue, *(gdouble*)value);
+  case G_TYPE_DOUBLE:
+      g_value_set_double (gvalue, (gdouble)value->v_double);
       break;
-    case G_TYPE_BOOLEAN:
-      g_value_set_boolean (gvalue, *(gboolean*)value);
+  case G_TYPE_BOOLEAN:
+      g_value_set_boolean (gvalue, (gboolean)value->v_long);
       break;
-    case G_TYPE_STRING:
-      g_value_set_string (gvalue, *(gchar**)value);
+  case G_TYPE_STRING:
+      g_value_set_string (gvalue, (gchar*)value->v_pointer);
       break;
-    case G_TYPE_CHAR:
-      g_value_set_char (gvalue, *(gchar*)value);
+  case G_TYPE_CHAR:
+      g_value_set_char (gvalue, (gchar)value->v_long);
       break;
-    case G_TYPE_UCHAR:
-      g_value_set_uchar (gvalue, *(guchar*)value);
+  case G_TYPE_UCHAR:
+      g_value_set_uchar (gvalue, (guchar)value->v_ulong);
       break;
-    case G_TYPE_UINT:
-      g_value_set_uint (gvalue, *(guint*)value);
+  case G_TYPE_UINT:
+      g_value_set_uint (gvalue, (guint)value->v_ulong);
       break;
-    case G_TYPE_POINTER:
-      g_value_set_pointer (gvalue, *(gpointer*)value);
+  case G_TYPE_POINTER:
+      g_value_set_pointer (gvalue, (gpointer)value->v_pointer);
       break;
-    case G_TYPE_LONG:
-      g_value_set_long (gvalue, *(glong*)value);
+  case G_TYPE_LONG:
+      g_value_set_long (gvalue, (glong)value->v_long);
       break;
-    case G_TYPE_ULONG:
-      g_value_set_ulong (gvalue, *(gulong*)value);
+  case G_TYPE_ULONG:
+      g_value_set_ulong (gvalue, (gulong)value->v_ulong);
       break;
-    case G_TYPE_INT64:
-      g_value_set_int64 (gvalue, *(gint64*)value);
+  case G_TYPE_INT64:
+      g_value_set_int64 (gvalue, (gint64)value->v_int64);
       break;
-    case G_TYPE_UINT64:
-      g_value_set_uint64 (gvalue, *(guint64*)value);
+  case G_TYPE_UINT64:
+      g_value_set_uint64 (gvalue, (guint64)value->v_uint64);
       break;
-    case G_TYPE_BOXED:
-      g_value_set_boxed (gvalue, *(gpointer*)value);
+  case G_TYPE_BOXED:
+      g_value_set_boxed (gvalue, (gpointer)value->v_pointer);
       break;
-    default:
-      g_warning ("Unsupported fundamental type: %s",
-                g_type_name (g_type_fundamental (G_VALUE_TYPE (gvalue))));
-    }
+  default:
+    g_warning ("Unsupported fundamental type: %s",
+	       g_type_name (g_type_fundamental (G_VALUE_TYPE (gvalue))));
+  }
+
 }
 
 void
@@ -149,6 +213,7 @@ gi_cclosure_marshal_generic (GClosure *closure,
                              gpointer invocation_hint,
                              gpointer marshal_data)
 {
+  GIArgument return_ffi_value;
   ffi_type *rtype;
   void *rvalue;
   int n_args;
@@ -160,15 +225,16 @@ gi_cclosure_marshal_generic (GClosure *closure,
 
   if (return_gvalue && G_VALUE_TYPE (return_gvalue))
     {
+      rtype = g_value_to_ffi_return_type (return_gvalue, &return_ffi_value,
+					  &rvalue);
       rtype = value_to_ffi_type (return_gvalue, &rvalue);
     }
   else
     {
       rtype = &ffi_type_void;
+      rvalue = &return_ffi_value.v_long;
     }
 
-  rvalue = g_alloca (MAX (rtype->size, sizeof (ffi_arg)));
-
   n_args = n_param_values + 1;
   atypes = g_alloca (sizeof (ffi_type *) * n_args);
   args =  g_alloca (sizeof (gpointer) * n_args);
@@ -204,5 +270,5 @@ gi_cclosure_marshal_generic (GClosure *closure,
   ffi_call (&cif, marshal_data ? marshal_data : cc->callback, rvalue, args);
 
   if (return_gvalue && G_VALUE_TYPE (return_gvalue))
-    value_from_ffi_type (return_gvalue, rvalue);
+    g_value_from_ffi_value (return_gvalue, &return_ffi_value);
 }



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