[pygobject] fix marshaling of arrays of GVariants
- From: Martin Pitt <martinpitt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pygobject] fix marshaling of arrays of GVariants
- Date: Tue, 25 Oct 2011 07:16:47 +0000 (UTC)
commit c7aa0e79dfb4c1092c51ae1464b8414083b4f3fc
Author: Mikkel Kamstrup Erlandsen <mikkel kamstrup canonical com>
Date: Tue Oct 4 12:28:26 2011 +0200
fix marshaling of arrays of GVariants
Add unit tests for marshaling of arrays of variants with all
transfer modes. Requires latest gobject-introspection.
Plug potential leaks of GArray data members
Fix calling of wrong cleanup_from_py for arrays
Simplify and fix logic for cleaning up arrays both in from_py()
and to_py() code paths.
https://bugzilla.gnome.org/show_bug.cgi?id=638915
Signed-off-by: Martin Pitt <martin pitt ubuntu com>
gi/pygi-cache.c | 2 +-
gi/pygi-marshal-cleanup.c | 81 +++++++++++++++++++++++++++++----------------
gi/pygi-marshal-from-py.c | 10 ++++-
gi/pygi-marshal-to-py.c | 13 ++++++-
tests/test_gi.py | 14 +++++++-
5 files changed, 85 insertions(+), 35 deletions(-)
---
diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c
index 41ca32c..5dc811a 100644
--- a/gi/pygi-cache.c
+++ b/gi/pygi-cache.c
@@ -498,7 +498,7 @@ _arg_cache_from_py_array_setup (PyGIArgCache *arg_cache,
callable_cache->args_cache[seq_cache->len_arg_index] = child_cache;
}
- arg_cache->from_py_cleanup = _pygi_marshal_cleanup_to_py_array;
+ arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array;
return TRUE;
}
diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c
index 8ed9bdb..f80ebfa 100644
--- a/gi/pygi-marshal-cleanup.c
+++ b/gi/pygi-marshal-cleanup.c
@@ -273,6 +273,37 @@ _pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state,
data);
}
+static GArray*
+_wrap_c_array (PyGIInvokeState *state,
+ PyGISequenceCache *sequence_cache,
+ gpointer data)
+{
+ GArray *array_;
+ gsize len;
+
+ if (sequence_cache->fixed_size >= 0) {
+ len = sequence_cache->fixed_size;
+ } else if (sequence_cache->is_zero_terminated) {
+ len = g_strv_length ((gchar **)data);
+ } else {
+ GIArgument *len_arg = state->args[sequence_cache->len_arg_index];
+ len = len_arg->v_long;
+ }
+
+ array_ = g_array_new (FALSE,
+ FALSE,
+ sequence_cache->item_size);
+
+ if (array_ == NULL)
+ return NULL;
+
+ g_free (array_->data);
+ array_->data = data;
+ array_->len = len;
+
+ return array_;
+}
+
void
_pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
@@ -286,26 +317,11 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
/* If this isn't a garray create one to help process variable sized
array elements */
if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
- gsize len;
- if (sequence_cache->fixed_size >= 0) {
- len = sequence_cache->fixed_size;
- } else if (sequence_cache->is_zero_terminated) {
- len = g_strv_length ((gchar **)data);
- } else {
- GIArgument *len_arg = state->args[sequence_cache->len_arg_index];
- len = len_arg->v_long;
- }
-
- array_ = g_array_new (FALSE,
- FALSE,
- sequence_cache->item_size);
-
+ array_ = _wrap_c_array (state, sequence_cache, data);
+
if (array_ == NULL)
return;
-
- array_->data = data;
- array_->len = len;
-
+
} else {
array_ = (GArray *) data;
}
@@ -324,12 +340,12 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
}
}
- if (state->failed ||
- arg_cache->transfer == GI_TRANSFER_NOTHING ||
- arg_cache->transfer == GI_TRANSFER_CONTAINER) {
+ /* Only free the array when we didn't transfer ownership */
+ if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
+ g_array_free (array_, arg_cache->transfer == GI_TRANSFER_NOTHING);
+ } else if (state->failed ||
+ arg_cache->transfer == GI_TRANSFER_NOTHING) {
g_array_free (array_, TRUE);
- } else if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
- g_array_free (array_, FALSE);
}
}
}
@@ -343,12 +359,20 @@ _pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state,
PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
- arg_cache->transfer == GI_TRANSFER_CONTAINER) {
- GArray *array_ = (GArray *) data;
+ arg_cache->transfer == GI_TRANSFER_CONTAINER) {
+ GArray *array_;
+ PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
+ /* If this isn't a garray create one to help process variable sized
+ array elements */
if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
- g_free (data);
- return;
+ array_ = _wrap_c_array (state, sequence_cache, data);
+
+ if (array_ == NULL)
+ return;
+
+ } else {
+ array_ = (GArray *) data;
}
if (sequence_cache->item_cache->to_py_cleanup != NULL) {
@@ -363,8 +387,7 @@ _pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state,
}
}
- if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
- g_array_free (array_, TRUE);
+ g_array_free (array_, TRUE);
}
}
diff --git a/gi/pygi-marshal-from-py.c b/gi/pygi-marshal-from-py.c
index 1f807b4..0a94ffe 100644
--- a/gi/pygi-marshal-from-py.c
+++ b/gi/pygi-marshal-from-py.c
@@ -831,8 +831,14 @@ _pygi_marshal_from_py_array (PyGIInvokeState *state,
PyGIMarshalCleanupFunc from_py_cleanup = item_arg_cache->from_py_cleanup;
gboolean is_boxed = g_type_is_a (item_iface_cache->g_type, G_TYPE_BOXED);
gboolean is_gvalue = item_iface_cache->g_type == G_TYPE_VALUE;
-
- if (!is_boxed || is_gvalue) {
+ gboolean is_gvariant = item_iface_cache->g_type == G_TYPE_VARIANT;
+
+ if (is_gvariant) {
+ /* Item size will always be that of a pointer,
+ * 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) {
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);
diff --git a/gi/pygi-marshal-to-py.c b/gi/pygi-marshal-to-py.c
index 48dfa08..984e7c1 100644
--- a/gi/pygi-marshal-to-py.c
+++ b/gi/pygi-marshal-to-py.c
@@ -292,7 +292,8 @@ _pygi_marshal_to_py_array (PyGIInvokeState *state,
return NULL;
}
-
+
+ g_free (array_->data);
array_->data = arg->v_pointer;
array_->len = len;
}
@@ -331,10 +332,18 @@ _pygi_marshal_to_py_array (PyGIInvokeState *state,
item_arg.v_pointer = g_ptr_array_index ( ( GPtrArray *)array_, i);
} else if (item_arg_cache->type_tag == GI_TYPE_TAG_INTERFACE) {
PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *) item_arg_cache;
+ gboolean is_gvariant = iface_cache->g_type == G_TYPE_VARIANT;
+ // FIXME: This probably doesn't work with boxed types or gvalues. See fx. _pygi_marshal_from_py_array()
switch (g_base_info_get_type (iface_cache->interface_info)) {
case GI_INFO_TYPE_STRUCT:
- if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) {
+ if (is_gvariant) {
+ g_assert (item_size == sizeof (gpointer));
+ if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+ item_arg.v_pointer = g_variant_ref_sink (g_array_index (array_, gpointer, i));
+ else
+ item_arg.v_pointer = g_array_index (array_, gpointer, i);
+ } else if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) {
gpointer *_struct = g_malloc (item_size);
memcpy (_struct, array_->data + i * item_size,
item_size);
diff --git a/tests/test_gi.py b/tests/test_gi.py
index dd91cb8..11ee2a4 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -10,7 +10,7 @@ import shutil
import os
import locale
import subprocess
-from gi.repository import GObject
+from gi.repository import GObject, GLib
from gi.repository import GIMarshallingTests
@@ -769,6 +769,18 @@ class TestArray(unittest.TestCase):
def test_gstrv_inout(self):
self.assertEquals(['-1', '0', '1', '2'], GIMarshallingTests.gstrv_inout(['0', '1', '2']))
+
+ def test_array_gvariant_none_in(self):
+ v = [GLib.Variant("i", 27), GLib.Variant("s", "Hello")]
+ self.assertEquals([27, "Hello"], map(GLib.Variant.unpack, GIMarshallingTests.array_gvariant_none_in(v)))
+
+ def test_array_gvariant_container_in(self):
+ v = [GLib.Variant("i", 27), GLib.Variant("s", "Hello")]
+ self.assertEquals([27, "Hello"], map(GLib.Variant.unpack, GIMarshallingTests.array_gvariant_none_in(v)))
+
+ def test_array_gvariant_full_in(self):
+ v = [GLib.Variant("i", 27), GLib.Variant("s", "Hello")]
+ self.assertEquals([27, "Hello"], map(GLib.Variant.unpack, GIMarshallingTests.array_gvariant_none_in(v)))
class TestGArray(unittest.TestCase):
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]