Commit d7d28d71 authored by Martin Pitt's avatar Martin Pitt
Browse files

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.
parent 27ac9c1d
......@@ -336,11 +336,20 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
PyGIMarshalCleanupFunc cleanup_func =
for(i = 0; i < len; i++) {
cleanup_func (state,
(array_ != NULL) ? g_array_index (array_, gpointer, i) : g_ptr_array_index (ptr_array_, i),
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 */
item = array_->data + i * sequence_cache->item_size;
cleanup_func (state, sequence_cache->item_cache, item, TRUE);
......@@ -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 {
......@@ -1046,6 +1046,14 @@ class TestGValue(unittest.TestCase):
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):
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment