summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Feltman <sfeltman@src.gnome.org>2013-10-06 21:54:15 -0700
committerSimon Feltman <sfeltman@src.gnome.org>2013-10-07 17:59:22 -0700
commit31263ac117027446c8e2fd1b56d7e348384aabef (patch)
tree55bd41d9959521e0d92e41baeffbd05c2433c858
parentc9580ce1156789221aa19b00c7aab404db5431b5 (diff)
downloadpygobject-31263ac117027446c8e2fd1b56d7e348384aabef.tar.gz
Fix to Python marshaling leaks for arrays holding GVariants
Add early check for array items holding pointers and simply assign the pointer to GIArgument.v_pointer prior giving it to the per-item marshaler. This simplifies marshaling and fixes leaks regarding arrays of GVariants by removing the unneeded g_variant_ref_sink (variants are always pointers). Conditionalize the use of g_variant_ref_sink based on transfer mode in the per-item marshaler. This fixes a reference leak where we are given ownership of the variant (transfer full) but added a new ref anyway. https://bugzilla.gnome.org/show_bug.cgi?id=693402
-rw-r--r--gi/pygi-marshal-to-py.c34
1 files changed, 18 insertions, 16 deletions
diff --git a/gi/pygi-marshal-to-py.c b/gi/pygi-marshal-to-py.c
index 2dc7f71b..2c7a8de2 100644
--- a/gi/pygi-marshal-to-py.c
+++ b/gi/pygi-marshal-to-py.c
@@ -351,36 +351,35 @@ _pygi_marshal_to_py_array (PyGIInvokeState *state,
item_size = g_array_get_element_size (array_);
for (i = 0; i < array_->len; i++) {
- GIArgument item_arg;
+ GIArgument item_arg = {0};
PyObject *py_item;
+ /* If we are receiving an array of pointers, simply assign the pointer
+ * and move on, letting the per-item marshaler deal with the
+ * various transfer modes and ref counts (e.g. g_variant_ref_sink).
+ */
if (seq_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
item_arg.v_pointer = g_ptr_array_index ( ( GPtrArray *)array_, i);
+
+ } else if (item_arg_cache->is_pointer) {
+ item_arg.v_pointer = g_array_index (array_, gpointer, 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 (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 && !item_arg_cache->is_pointer &&
+ if (arg_cache->transfer == GI_TRANSFER_EVERYTHING &&
!g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) {
/* array elements are structs */
gpointer *_struct = g_malloc (item_size);
memcpy (_struct, array_->data + i * item_size,
item_size);
item_arg.v_pointer = _struct;
- } else if (item_arg_cache->is_pointer)
- /* array elements are pointers to values */
- item_arg.v_pointer = g_array_index (array_, gpointer, i);
- else
+ } else {
item_arg.v_pointer = array_->data + i * item_size;
+ }
break;
default:
item_arg.v_pointer = g_array_index (array_, gpointer, i);
@@ -858,10 +857,13 @@ _pygi_marshal_to_py_interface_struct (GIArgument *arg,
transfer == GI_TRANSFER_EVERYTHING);
}
} else if (g_type_is_a (g_type, G_TYPE_VARIANT)) {
- /* Note we do not use transfer for the structs free_on_dealloc because
- * GLib.Variant overrides __del__ to call "g_variant_unref". */
+ /* Note: sink the variant (add a ref) only if we are not transfered ownership.
+ * GLib.Variant overrides __del__ which will then call "g_variant_unref" for
+ * cleanup in either case. */
if (py_type) {
- g_variant_ref_sink (arg->v_pointer);
+ if (transfer == GI_TRANSFER_NOTHING) {
+ g_variant_ref_sink (arg->v_pointer);
+ }
py_obj = _pygi_struct_new ((PyTypeObject *) py_type,
arg->v_pointer,
FALSE);