[gjs/309-fix-stuffed-pointer-marshalling: 2/2] arg: Fix GList and GHashTable marshalling on 64-bit big-endian



commit 93db285f3e1472eed9b8b4949493206e943acadb
Author: Philip Chimento <philip chimento gmail com>
Date:   Sat Apr 4 19:54:21 2020 -0700

    arg: Fix GList and GHashTable marshalling on 64-bit big-endian
    
    It is not correct to simply write to arg->v_pointer and read out a
    different member of the GIArgument union, or vice-versa. We were doing
    this when stuffing integers into pointers for storage in a GList,
    GSList, or GHashTable. In the case of 32-bit ints, this would read out
    the wrong half of the pointer on big-endian 64-bit architectures.
    
    Closes: #309

 gi/arg.cpp | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 113 insertions(+), 8 deletions(-)
---
diff --git a/gi/arg.cpp b/gi/arg.cpp
index 04bd3c8c..530bbd2d 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -278,6 +278,103 @@ static GITypeTag _g_type_info_get_storage_type(GITypeInfo* info) {
     return type_tag;
 }
 
+/* FIXME: This should be added to gobject-introspection */
+static void _g_type_info_argument_from_hash_pointer(GITypeInfo* info,
+                                                    void* hash_pointer,
+                                                    GIArgument* arg) {
+    GITypeTag type_tag = _g_type_info_get_storage_type(info);
+
+    switch (type_tag) {
+        case GI_TYPE_TAG_BOOLEAN:
+            arg->v_boolean = !!GPOINTER_TO_INT(hash_pointer);
+            break;
+        case GI_TYPE_TAG_INT8:
+            arg->v_int8 = (gint8)GPOINTER_TO_INT(hash_pointer);
+            break;
+        case GI_TYPE_TAG_UINT8:
+            arg->v_uint8 = (guint8)GPOINTER_TO_UINT(hash_pointer);
+            break;
+        case GI_TYPE_TAG_INT16:
+            arg->v_int16 = (gint16)GPOINTER_TO_INT(hash_pointer);
+            break;
+        case GI_TYPE_TAG_UINT16:
+            arg->v_uint16 = (guint16)GPOINTER_TO_UINT(hash_pointer);
+            break;
+        case GI_TYPE_TAG_INT32:
+            arg->v_int32 = (gint32)GPOINTER_TO_INT(hash_pointer);
+            break;
+        case GI_TYPE_TAG_UINT32:
+        case GI_TYPE_TAG_UNICHAR:
+            arg->v_uint32 = (guint32)GPOINTER_TO_UINT(hash_pointer);
+            break;
+        case GI_TYPE_TAG_GTYPE:
+            arg->v_size = GPOINTER_TO_SIZE(hash_pointer);
+            break;
+        case GI_TYPE_TAG_UTF8:
+        case GI_TYPE_TAG_FILENAME:
+        case GI_TYPE_TAG_INTERFACE:
+        case GI_TYPE_TAG_ARRAY:
+        case GI_TYPE_TAG_GLIST:
+        case GI_TYPE_TAG_GSLIST:
+        case GI_TYPE_TAG_GHASH:
+        case GI_TYPE_TAG_ERROR:
+            arg->v_pointer = hash_pointer;
+            break;
+        case GI_TYPE_TAG_INT64:
+        case GI_TYPE_TAG_UINT64:
+        case GI_TYPE_TAG_FLOAT:
+        case GI_TYPE_TAG_DOUBLE:
+        default:
+            g_critical("Unsupported type for pointer-stuffing: %s",
+                       g_type_tag_to_string(type_tag));
+            arg->v_pointer = hash_pointer;
+    }
+}
+
+/* FIXME: This should be added to gobject-introspection */
+GJS_USE
+static void* _g_type_info_hash_pointer_from_argument(GITypeInfo* info,
+                                                     GIArgument* arg) {
+    GITypeTag type_tag = _g_type_info_get_storage_type(info);
+
+    switch (type_tag) {
+        case GI_TYPE_TAG_BOOLEAN:
+            return GINT_TO_POINTER(arg->v_boolean);
+        case GI_TYPE_TAG_INT8:
+            return GINT_TO_POINTER(arg->v_int8);
+        case GI_TYPE_TAG_UINT8:
+            return GUINT_TO_POINTER(arg->v_uint8);
+        case GI_TYPE_TAG_INT16:
+            return GINT_TO_POINTER(arg->v_int16);
+        case GI_TYPE_TAG_UINT16:
+            return GUINT_TO_POINTER(arg->v_uint16);
+        case GI_TYPE_TAG_INT32:
+            return GINT_TO_POINTER(arg->v_int32);
+        case GI_TYPE_TAG_UINT32:
+        case GI_TYPE_TAG_UNICHAR:
+            return GUINT_TO_POINTER(arg->v_uint32);
+        case GI_TYPE_TAG_GTYPE:
+            return GSIZE_TO_POINTER(arg->v_size);
+        case GI_TYPE_TAG_UTF8:
+        case GI_TYPE_TAG_FILENAME:
+        case GI_TYPE_TAG_INTERFACE:
+        case GI_TYPE_TAG_ARRAY:
+        case GI_TYPE_TAG_GLIST:
+        case GI_TYPE_TAG_GSLIST:
+        case GI_TYPE_TAG_GHASH:
+        case GI_TYPE_TAG_ERROR:
+            return arg->v_pointer;
+        case GI_TYPE_TAG_INT64:
+        case GI_TYPE_TAG_UINT64:
+        case GI_TYPE_TAG_FLOAT:
+        case GI_TYPE_TAG_DOUBLE:
+        default:
+            g_critical("Unsupported type for pointer-stuffing: %s",
+                       g_type_tag_to_string(type_tag));
+            return arg->v_pointer;
+    }
+}
+
 GJS_JSAPI_RETURN_CONVENTION
 static bool
 gjs_array_to_g_list(JSContext   *context,
@@ -338,12 +435,15 @@ gjs_array_to_g_list(JSContext   *context,
             return false;
         }
 
+        void* hash_pointer =
+            _g_type_info_hash_pointer_from_argument(param_info, &elem_arg);
+
         if (list_type == GI_TYPE_TAG_GLIST) {
             /* GList */
-            list = g_list_prepend(list, elem_arg.v_pointer);
+            list = g_list_prepend(list, hash_pointer);
         } else {
             /* GSList */
-            slist = g_slist_prepend(slist, elem_arg.v_pointer);
+            slist = g_slist_prepend(slist, hash_pointer);
         }
     }
 
@@ -582,8 +682,9 @@ gjs_object_to_g_hash(JSContext   *context,
             *heap_val = val_arg.v_double;
             val_ptr = heap_val;
         } else {
-            /* Other types are simply stuffed inside v_pointer */
-            val_ptr = val_arg.v_pointer;
+            // Other types are simply stuffed inside the pointer
+            val_ptr = _g_type_info_hash_pointer_from_argument(val_param_info,
+                                                              &val_arg);
         }
 
         g_hash_table_insert(result, key_ptr, val_ptr);
@@ -2242,7 +2343,8 @@ gjs_array_from_g_list (JSContext             *context,
     i = 0;
     if (list_tag == GI_TYPE_TAG_GLIST) {
         for ( ; list != NULL; list = list->next) {
-            arg.v_pointer = list->data;
+            _g_type_info_argument_from_hash_pointer(param_info, list->data,
+                                                    &arg);
             if (!elems.growBy(1)) {
                 JS_ReportOutOfMemory(context);
                 return false;
@@ -2255,7 +2357,8 @@ gjs_array_from_g_list (JSContext             *context,
         }
     } else {
         for ( ; slist != NULL; slist = slist->next) {
-            arg.v_pointer = slist->data;
+            _g_type_info_argument_from_hash_pointer(param_info, slist->data,
+                                                    &arg);
             if (!elems.growBy(1)) {
                 JS_ReportOutOfMemory(context);
                 return false;
@@ -2646,8 +2749,8 @@ gjs_object_from_g_hash (JSContext             *context,
     JS::RootedString keystr(context);
 
     g_hash_table_iter_init(&iter, hash);
-    while (g_hash_table_iter_next
-           (&iter, &keyarg.v_pointer, &valarg.v_pointer)) {
+    void* val_pointer;
+    while (g_hash_table_iter_next(&iter, &keyarg.v_pointer, &val_pointer)) {
         if (!gjs_value_from_g_argument(context, &keyjs,
                                        key_param_info, &keyarg,
                                        true))
@@ -2661,6 +2764,8 @@ gjs_object_from_g_hash (JSContext             *context,
         if (!keyutf8)
             return false;
 
+        _g_type_info_argument_from_hash_pointer(val_param_info, val_pointer,
+                                                &valarg);
         if (!gjs_value_from_g_argument(context, &valjs,
                                        val_param_info, &valarg,
                                        true))


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