[gjs] Don't release too much when releasing arrays



commit fa8b8447fbbf1fd421621751b57a4d2e11f7bb2d
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Sat Jul 2 16:58:16 2011 +0200

    Don't release too much when releasing arrays
    
    The functions that released out arrays were iterating over
    pointer sized values, irrespective of the actual element size.
    Fix that by checking that the element is actually a pointer
    (everything else requires no release, except for the actual array
    block)
    
    https://bugzilla.gnome.org/show_bug.cgi?id=652753

 gi/arg.c                       |  103 ++++++++++++++++++++++++++++++++-------
 test/js/testEverythingBasic.js |   17 ++++++-
 2 files changed, 100 insertions(+), 20 deletions(-)
---
diff --git a/gi/arg.c b/gi/arg.c
index 0170845..c8d769b 100644
--- a/gi/arg.c
+++ b/gi/arg.c
@@ -198,6 +198,7 @@ type_needs_release (GITypeInfo *type_info,
 
         case GI_INFO_TYPE_STRUCT:
         case GI_INFO_TYPE_ENUM:
+        case GI_INFO_TYPE_FLAGS:
         case GI_INFO_TYPE_OBJECT:
         case GI_INFO_TYPE_INTERFACE:
         case GI_INFO_TYPE_UNION:
@@ -233,6 +234,49 @@ type_needs_release (GITypeInfo *type_info,
     }
 }
 
+/* Check if an argument of the given needs to be released if we obtained it
+ * from out argument (or the return value), and we're transferring ownership
+ */
+static JSBool
+type_needs_out_release(GITypeInfo *type_info,
+                       GITypeTag   type_tag)
+{
+    switch (type_tag) {
+    case GI_TYPE_TAG_UTF8:
+    case GI_TYPE_TAG_FILENAME:
+    case GI_TYPE_TAG_ARRAY:
+    case GI_TYPE_TAG_GLIST:
+    case GI_TYPE_TAG_GSLIST:
+    case GI_TYPE_TAG_GHASH:
+        return TRUE;
+    case GI_TYPE_TAG_INTERFACE: {
+        GIBaseInfo* interface_info;
+        GIInfoType interface_type;
+        gboolean needs_release;
+
+        interface_info = g_type_info_get_interface(type_info);
+        g_assert(interface_info != NULL);
+
+        interface_type = g_base_info_get_type(interface_info);
+
+        switch(interface_type) {
+        case GI_INFO_TYPE_ENUM:
+        case GI_INFO_TYPE_FLAGS:
+            needs_release = FALSE;
+
+        default:
+            needs_release = TRUE;
+        }
+
+        g_base_info_unref(interface_info);
+
+        return needs_release;
+    }
+    default:
+        return FALSE;
+    }
+}
+
 static JSBool
 gjs_array_to_g_list(JSContext   *context,
                     jsval        array_value,
@@ -2576,19 +2620,38 @@ gjs_g_arg_release_internal(JSContext  *context,
             case GI_TYPE_TAG_GSLIST:
             case GI_TYPE_TAG_ARRAY:
             case GI_TYPE_TAG_GHASH:
-                if (transfer != GI_TRANSFER_CONTAINER) {
-                    g_assert (g_type_info_is_zero_terminated (type_info));
-                    gpointer *array;
-                    GArgument elem;
-
-                    for (array = arg->v_pointer; *array; array++) {
-                        elem.v_pointer = *array;
-                        if (!gjs_g_arg_release_internal(context,
-                                                        GI_TRANSFER_EVERYTHING,
-                                                        param_info,
-                                                        element_type,
-                                                        &elem)) {
-                            failed = JS_TRUE;
+                if (transfer != GI_TRANSFER_CONTAINER
+                    && type_needs_out_release(param_info, element_type)) {
+                    if (g_type_info_is_zero_terminated (type_info)) {
+                        gpointer *array;
+                        GArgument elem;
+
+                        for (array = arg->v_pointer; *array; array++) {
+                            elem.v_pointer = *array;
+                            if (!gjs_g_arg_release_internal(context,
+                                                            GI_TRANSFER_EVERYTHING,
+                                                            param_info,
+                                                            element_type,
+                                                            &elem)) {
+                                failed = JS_TRUE;
+                            }
+                        }
+                    } else {
+                        gint len = g_type_info_get_array_fixed_size(type_info);
+                        gint i;
+                        GArgument elem;
+
+                        g_assert(len != -1);
+
+                        for (i = 0; i < len; i++) {
+                            elem.v_pointer = ((gpointer*)arg->v_pointer)[i];
+                            if (!gjs_g_arg_release_internal(context,
+                                                            GI_TRANSFER_EVERYTHING,
+                                                            param_info,
+                                                            element_type,
+                                                            &elem)) {
+                                failed = TRUE;
+                            }
                         }
                     }
                 }
@@ -2632,7 +2695,7 @@ gjs_g_arg_release_internal(JSContext  *context,
             case GI_TYPE_TAG_GHASH:
                 if (transfer == GI_TRANSFER_CONTAINER) {
                     g_array_free((GArray*) arg->v_pointer, TRUE);
-                } else {
+                } else if (type_needs_out_release (param_info, element_type)) {
                     GArray *array = arg->v_pointer;
                     guint i;
 
@@ -2640,10 +2703,11 @@ gjs_g_arg_release_internal(JSContext  *context,
                         GArgument arg;
 
                         arg.v_pointer = g_array_index (array, gpointer, i);
-                        gjs_g_argument_release(context,
-                                               transfer,
-                                               param_info,
-                                               &arg);
+                        gjs_g_arg_release_internal(context,
+                                                   transfer,
+                                                   param_info,
+                                                   element_type,
+                                                   &arg);
                     }
 
                     g_array_free (array, TRUE);
@@ -2876,7 +2940,8 @@ gjs_g_argument_release_out_array (JSContext  *context,
     param_type = g_type_info_get_param_type(type_info, 0);
     type_tag = g_type_info_get_tag(param_type);
 
-    if (transfer != GI_TRANSFER_CONTAINER) {
+    if (transfer != GI_TRANSFER_CONTAINER &&
+        type_needs_out_release(param_type, type_tag)) {
         for (i = 0; i < length; i++) {
             elem.v_pointer = array[i];
             if (!gjs_g_arg_release_internal(context,
diff --git a/test/js/testEverythingBasic.js b/test/js/testEverythingBasic.js
index 264b216..9e49cbf 100644
--- a/test/js/testEverythingBasic.js
+++ b/test/js/testEverythingBasic.js
@@ -295,6 +295,12 @@ function testArrayIn() {
 }
 
 function testArrayOut() {
+    function arrayEqual(ref, res) {
+	assertEquals(ref.length, res.length);
+	for (let i = 0; i < ref.length; i++)
+	    assertEquals(ref[i], res[i]);
+    }
+
     let array =  Everything.test_array_fixed_size_int_out();
     assertEquals(0, array[0]);
     assertEquals(4, array[4]);
@@ -302,7 +308,16 @@ function testArrayOut() {
     assertEquals(0, array[0]);
     assertEquals(4, array[4]);
 
-    // FIXME: test_array_int_full_out and test_array_int_none_out unimplemented
+    array = Everything.test_array_int_none_out();
+    arrayEqual([1, 2, 3, 4, 5], array);
+
+    array = Everything.test_array_int_full_out();
+    arrayEqual([0, 1, 2, 3, 4], array);
+
+    array = Everything.test_array_int_null_out();
+    assertEquals(0, array.length);
+
+    Everything.test_array_int_null_in(null);
 }
 
 /* GHash type */



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