[pygobject] Fix Python to C marshalling of GValue arrays



commit d7d28d717e38c0546529b09b8b571a5cc631c5b5
Author: Martin Pitt <martin pitt ubuntu com>
Date:   Wed Mar 14 22:52:47 2012 +0100

    Fix Python to C marshalling of GValue arrays
    
    For GValues we cannot just copy the GValue memory in
    _pygi_marshal_from_py_array(), as the from_py_cleanup() function clears and
    releases the GValue and with it its v_pointer. Use g_value_copy() to copy by
    value instead.
    
    This uncovered another bug in _pygi_marshal_cleanup_from_py_array(): It always
    assumed that C arrays contained pointers, but this is not the case for GValue
    arrays: these are actual struct arrays, not struct pointer arrays (cf. their
    construction in _pygi_marshal_from_py_array()). Check if an array contains
    pointers or values and compute the correct array item pointer for both cases.
    
    Also add a corresponding test case for marshalling GValue arrays from C back to
    Python, which works fine.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=672065

 gi/pygi-marshal-cleanup.c |   19 ++++++++++++++-----
 gi/pygi-marshal-from-py.c |   13 ++++++++++++-
 tests/test_gi.py          |    8 ++++++++
 3 files changed, 34 insertions(+), 6 deletions(-)
---
diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c
index e65731a..d580161 100644
--- a/gi/pygi-marshal-cleanup.c
+++ b/gi/pygi-marshal-cleanup.c
@@ -336,11 +336,20 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
             PyGIMarshalCleanupFunc cleanup_func =
                 sequence_cache->item_cache->from_py_cleanup;
 
-            for(i = 0; i < len; i++) {
-                cleanup_func (state,
-                              sequence_cache->item_cache,
-                              (array_ != NULL) ? g_array_index (array_, gpointer, i) : g_ptr_array_index (ptr_array_, i),
-                              TRUE);
+            for (i = 0; i < len; i++) {
+                gpointer item;
+
+                /* case 1: GPtrArray */
+                if (ptr_array_ != NULL)
+                    item = g_ptr_array_index (ptr_array_, i);
+                /* case 2: C array or GArray with object pointers */
+                else if (sequence_cache->item_cache->is_pointer)
+                    item = g_array_index (array_, gpointer, i);
+                /* case 3: C array or GArray with simple types or structs */
+                else
+                    item = array_->data + i * sequence_cache->item_size;
+
+                cleanup_func (state, sequence_cache->item_cache, item, TRUE);
             }
         }
 
diff --git a/gi/pygi-marshal-from-py.c b/gi/pygi-marshal-from-py.c
index 1926b35..92cd499 100644
--- a/gi/pygi-marshal-from-py.c
+++ b/gi/pygi-marshal-from-py.c
@@ -839,8 +839,19 @@ _pygi_marshal_from_py_array (PyGIInvokeState   *state,
                          * since GVariants are opaque hence always passed by ref */
                         g_assert (item_size == sizeof (item.v_pointer));
                         g_array_insert_val (array_, i, item.v_pointer);
-                    } else if (!is_boxed || is_gvalue) {
+                    } else if (is_gvalue) {
+                        GValue* dest = (GValue*) (array_->data + (i * item_size));
+                        memset (dest, 0, item_size);
+                        if (item.v_pointer != NULL) {
+                            g_value_init (dest, G_VALUE_TYPE ((GValue*) item.v_pointer));
+                            g_value_copy ((GValue*) item.v_pointer, dest);
+                        }
+
+                        if (from_py_cleanup)
+                            from_py_cleanup (state, item_arg_cache, item.v_pointer, TRUE);
+                    } else if (!is_boxed) {
                         memcpy (array_->data + (i * item_size), item.v_pointer, item_size);
+
                         if (from_py_cleanup)
                             from_py_cleanup (state, item_arg_cache, item.v_pointer, TRUE);
                     } else {
diff --git a/tests/test_gi.py b/tests/test_gi.py
index be18af5..edbe461 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -1046,6 +1046,14 @@ class TestGValue(unittest.TestCase):
         value.set_int(42)
         self.assertEquals('42', GIMarshallingTests.gvalue_inout(value))
 
+    def test_gvalue_flat_array_in(self):
+        # the function already asserts the correct values
+        GIMarshallingTests.gvalue_flat_array([42, "42", True])
+
+    def test_gvalue_flat_array_out(self):
+        values = GIMarshallingTests.return_gvalue_flat_array()
+        self.assertEqual(values, [42, '42', True])
+
 
 class TestGClosure(unittest.TestCase):
 



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