[pygobject] Add cleanup_data argument used for Python to C marshaler cleanup



commit 7407367f424595c2780a2d6a47d936ad0bd91735
Author: Simon Feltman <sfeltman src gnome org>
Date:   Mon Oct 7 14:11:39 2013 -0700

    Add cleanup_data argument used for Python to C marshaler cleanup
    
    Add a new output argument to all from_py marshalers which is used for
    keeping track of marshaling data that later needs cleanup. Previously most
    marshalers would rely on the GIArgument->v_pointer as the means for data
    cleanup. However, this pointer would get clobbered in the case of
    bi-directional arguments (inout) and the memory lost.
    Use the new cleanup_data for storing temporarily wrapped C arrays so we
    don't need to re-calculate the length argument during cleanup.
    
    Additionally delay the from_py marshaling cleanup function until after
    _invoke_marshal_out_args is called. This gives inout arguments which don't
    modify the pointer sufficient time to exist until they marshaled back to
    Python (gi_marshalling_tests_gvalue_inout).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=693402

 gi/pygi-argument.c            |    4 +-
 gi/pygi-cache.h               |    3 +-
 gi/pygi-invoke-state-struct.h |    7 +-
 gi/pygi-invoke.c              |   20 +++--
 gi/pygi-marshal-cleanup.c     |   43 +++++-------
 gi/pygi-marshal-from-py.c     |  160 +++++++++++++++++++++++++++-------------
 gi/pygi-marshal-from-py.h     |   45 ++++++++----
 7 files changed, 177 insertions(+), 105 deletions(-)
---
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index 3b857be..6378892 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -894,11 +894,13 @@ _pygi_argument_from_object (PyObject   *object,
 {
     GIArgument arg;
     GITypeTag type_tag;
+    gpointer cleanup_data = NULL;
 
     memset(&arg, 0, sizeof(GIArgument));
     type_tag = g_type_info_get_tag (type_info);
 
-    if (_pygi_marshal_from_py_basic_type (object, &arg, type_tag, transfer) ||
+    /* Ignores cleanup data for now. */
+    if (_pygi_marshal_from_py_basic_type (object, &arg, type_tag, transfer, &cleanup_data) ||
             PyErr_Occurred()) {
         return arg;
     }
diff --git a/gi/pygi-cache.h b/gi/pygi-cache.h
index 1b32381..745d0a1 100644
--- a/gi/pygi-cache.h
+++ b/gi/pygi-cache.h
@@ -36,7 +36,8 @@ typedef gboolean (*PyGIMarshalFromPyFunc) (PyGIInvokeState   *state,
                                            PyGICallableCache *callable_cache,
                                            PyGIArgCache      *arg_cache,
                                            PyObject          *py_arg,
-                                           GIArgument        *arg);
+                                           GIArgument        *arg,
+                                           gpointer          *cleanup_data);
 
 typedef PyObject *(*PyGIMarshalToPyFunc) (PyGIInvokeState   *state,
                                           PyGICallableCache *callable_cache,
diff --git a/gi/pygi-invoke-state-struct.h b/gi/pygi-invoke-state-struct.h
index 1d9e49c..139b878 100644
--- a/gi/pygi-invoke-state-struct.h
+++ b/gi/pygi-invoke-state-struct.h
@@ -18,9 +18,10 @@ typedef struct _PyGIInvokeState
     GIArgument **args;
     GIArgument *in_args;
 
-    /* Generic array allocated to the same length as args
-     * for use as extra per-arg state data. */
-    gpointer *args_data;
+    /* Array of pointers allocated to the same length as args which holds from_py
+     * marshaler cleanup data.
+     */
+    gpointer *args_cleanup_data;
 
     /* Out args and out values
      * In order to pass a parameter and get something back out in C
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c
index 9dc40d6..675b0ef 100644
--- a/gi/pygi-invoke.c
+++ b/gi/pygi-invoke.c
@@ -350,8 +350,8 @@ _invoke_state_init_from_callable_cache (PyGIInvokeState *state,
         return FALSE;
     }
 
-    state->args_data = g_slice_alloc0 (_pygi_callable_cache_args_len (cache) * sizeof (gpointer));
-    if (state->args_data == NULL && _pygi_callable_cache_args_len (cache) != 0) {
+    state->args_cleanup_data = g_slice_alloc0 (_pygi_callable_cache_args_len (cache) * sizeof (gpointer));
+    if (state->args_cleanup_data == NULL && _pygi_callable_cache_args_len (cache) != 0) {
         PyErr_NoMemory();
         return FALSE;
     }
@@ -383,7 +383,7 @@ static inline void
 _invoke_state_clear (PyGIInvokeState *state, PyGICallableCache *cache)
 {
     g_slice_free1 (_pygi_callable_cache_args_len (cache) * sizeof(GIArgument *), state->args);
-    g_slice_free1 (_pygi_callable_cache_args_len (cache) * sizeof(gpointer), state->args_data);
+    g_slice_free1 (_pygi_callable_cache_args_len (cache) * sizeof(gpointer), state->args_cleanup_data);
     g_slice_free1 (cache->n_from_py_args * sizeof(GIArgument), state->in_args);
     g_slice_free1 (cache->n_to_py_args * sizeof(GIArgument), state->out_args);
     g_slice_free1 (cache->n_to_py_args * sizeof(GIArgument), state->out_values);
@@ -539,6 +539,8 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache)
             *c_arg = arg_cache->default_value;
         } else if (arg_cache->from_py_marshaller != NULL) {
             gboolean success;
+            gpointer cleanup_data = NULL;
+
             if (!arg_cache->allow_none && py_arg == Py_None) {
                 PyErr_Format (PyExc_TypeError,
                               "Argument %zd does not allow None as a value",
@@ -550,10 +552,12 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache)
                  return FALSE;
             }
             success = arg_cache->from_py_marshaller (state,
-                                                              cache,
-                                                              arg_cache,
-                                                              py_arg,
-                                                              c_arg);
+                                                     cache,
+                                                     arg_cache,
+                                                     py_arg,
+                                                     c_arg,
+                                                     &cleanup_data);
+            state->args_cleanup_data[i] = cleanup_data;
 
             if (!success) {
                 pygi_marshal_cleanup_args_from_py_parameter_fail (state,
@@ -701,9 +705,9 @@ pygi_callable_info_invoke (GIBaseInfo *info, PyObject *py_args,
     if (!_invoke_callable (&state, cache, info, function_ptr))
         goto err;
 
+    ret = _invoke_marshal_out_args (&state, cache);
     pygi_marshal_cleanup_args_from_py_marshal_success (&state, cache);
 
-    ret = _invoke_marshal_out_args (&state, cache);
     if (ret)
         pygi_marshal_cleanup_args_to_py_marshal_success (&state, cache);
 err:
diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c
index cd059a4..29ea617 100644
--- a/gi/pygi-marshal-cleanup.c
+++ b/gi/pygi-marshal-cleanup.c
@@ -94,23 +94,23 @@ pygi_marshal_cleanup_args_from_py_marshal_success (PyGIInvokeState   *state,
 {
     gssize i;
 
-    /* For in success, call cleanup for all GI_DIRECTION_IN values only. */
     for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) {
         PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (cache, i);
         PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup;
         PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args,
                                              arg_cache->py_arg_index);
+        gpointer cleanup_data = state->args_cleanup_data[i];
 
-        if (cleanup_func &&
-                arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON &&
-                    state->args[i]->v_pointer != NULL)
-            cleanup_func (state, arg_cache, py_arg, state->args[i]->v_pointer, TRUE);
-
-        if (cleanup_func &&
-                arg_cache->direction == PYGI_DIRECTION_BIDIRECTIONAL &&
-                    state->args_data[i] != NULL) {
-            cleanup_func (state, arg_cache, py_arg, state->args_data[i], TRUE);
-            state->args_data[i] = NULL;
+        /* Only cleanup using args_cleanup_data when available.
+         * It is the responsibility of the various "from_py" marshalers to return
+         * cleanup_data which is then passed into their respective cleanup function.
+         * PyGIInvokeState.args_cleanup_data stores this data (via _invoke_marshal_in_args)
+         * for the duration of the invoke up until this point.
+         */
+        if (cleanup_func && cleanup_data != NULL &&
+                arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) {
+            cleanup_func (state, arg_cache, py_arg, cleanup_data, TRUE);
+            state->args_cleanup_data[i] = NULL;
         }
     }
 }
@@ -213,9 +213,8 @@ _pygi_marshal_cleanup_from_py_utf8 (PyGIInvokeState *state,
                                     gpointer         data,
                                     gboolean         was_processed)
 {
-    /* We strdup strings so always free if we have processed this
-       parameter for input */
-    if (was_processed)
+    /* We strdup strings so free unless ownership is transferred to C. */
+    if (was_processed && arg_cache->transfer == GI_TRANSFER_NOTHING)
         g_free (data);
 }
 
@@ -270,8 +269,7 @@ _pygi_marshal_cleanup_from_py_interface_callback (PyGIInvokeState *state,
 {
     PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
     if (was_processed && callback_cache->scope == GI_SCOPE_TYPE_CALL) {
-        _pygi_invoke_closure_free (state->args_data[arg_cache->c_arg_index]);
-        state->args_data[arg_cache->c_arg_index] = NULL;
+        _pygi_invoke_closure_free (data);
     }
 }
 
@@ -366,15 +364,7 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
         GPtrArray *ptr_array_ = NULL;
         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) {
-            array_ = _wrap_c_array (state, sequence_cache, data);
-            
-            if (array_ == NULL)
-                return;
-            
-        } else if (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
+        if (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
             ptr_array_ = (GPtrArray *) data;
         } else {
             array_ = (GArray *) data;
@@ -418,6 +408,9 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
 
         /* Only free the array when we didn't transfer ownership */
         if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
+            /* always free the GArray wrapper created in from_py marshaling and
+             * passed back as cleanup_data
+             */
             g_array_free (array_, arg_cache->transfer == GI_TRANSFER_NOTHING);
         } else if (state->failed ||
                    arg_cache->transfer == GI_TRANSFER_NOTHING) {
diff --git a/gi/pygi-marshal-from-py.c b/gi/pygi-marshal-from-py.c
index df22863..a2b58cc 100644
--- a/gi/pygi-marshal-from-py.c
+++ b/gi/pygi-marshal-from-py.c
@@ -247,7 +247,8 @@ _pygi_marshal_from_py_void (PyGIInvokeState   *state,
                             PyGICallableCache *callable_cache,
                             PyGIArgCache      *arg_cache,
                             PyObject          *py_arg,
-                            GIArgument        *arg)
+                            GIArgument        *arg,
+                            gpointer          *cleanup_data)
 {
     g_warn_if_fail (arg_cache->transfer == GI_TRANSFER_NOTHING);
 
@@ -264,6 +265,7 @@ _pygi_marshal_from_py_void (PyGIInvokeState   *state,
         return FALSE;
     }
 
+    *cleanup_data = arg->v_pointer;
     return TRUE;
 }
 
@@ -408,7 +410,8 @@ _pygi_marshal_from_py_gtype (PyObject          *py_arg,
 
 static gboolean
 _pygi_marshal_from_py_utf8 (PyObject          *py_arg,
-                            GIArgument        *arg)
+                            GIArgument        *arg,
+                            gpointer          *cleanup_data)
 {
     gchar *string_;
 
@@ -437,12 +440,14 @@ _pygi_marshal_from_py_utf8 (PyObject          *py_arg,
     }
 
     arg->v_string = string_;
+    *cleanup_data = arg->v_string;
     return TRUE;
 }
 
 static gboolean
 _pygi_marshal_from_py_filename (PyObject          *py_arg,
-                                GIArgument        *arg)
+                                GIArgument        *arg,
+                                gpointer          *cleanup_data)
 {
     gchar *string_;
     GError *error = NULL;
@@ -476,6 +481,7 @@ _pygi_marshal_from_py_filename (PyObject          *py_arg,
         return FALSE;
     }
 
+    *cleanup_data = arg->v_string;
     return TRUE;
 }
 
@@ -626,7 +632,8 @@ gboolean
 _pygi_marshal_from_py_basic_type (PyObject   *object,   /* in */
                                   GIArgument *arg,      /* out */
                                   GITypeTag   type_tag,
-                                  GITransfer  transfer)
+                                  GITransfer  transfer,
+                                  gpointer   *cleanup_data /* out */)
 {
     switch (type_tag) {
         case GI_TYPE_TAG_VOID:
@@ -639,6 +646,7 @@ _pygi_marshal_from_py_basic_type (PyObject   *object,   /* in */
                     "See: https://bugzilla.gnome.org/show_bug.cgi?id=683599";);
             } else {
                 arg->v_pointer = PyLong_AsVoidPtr (object);
+                *cleanup_data = arg->v_pointer;
             }
             break;
         case GI_TYPE_TAG_INT8:
@@ -682,10 +690,10 @@ _pygi_marshal_from_py_basic_type (PyObject   *object,   /* in */
             return _pygi_marshal_from_py_unichar (object, arg);
 
         case GI_TYPE_TAG_UTF8:
-            return _pygi_marshal_from_py_utf8 (object, arg);
+            return _pygi_marshal_from_py_utf8 (object, arg, cleanup_data);
 
         case GI_TYPE_TAG_FILENAME:
-            return _pygi_marshal_from_py_filename (object, arg);
+            return _pygi_marshal_from_py_filename (object, arg, cleanup_data);
 
         default:
             return FALSE;
@@ -702,12 +710,14 @@ _pygi_marshal_from_py_basic_type_cache_adapter (PyGIInvokeState   *state,
                                                 PyGICallableCache *callable_cache,
                                                 PyGIArgCache      *arg_cache,
                                                 PyObject          *py_arg,
-                                                GIArgument        *arg)
+                                                GIArgument        *arg,
+                                                gpointer          *cleanup_data)
 {
     return _pygi_marshal_from_py_basic_type (py_arg,
                                              arg,
                                              arg_cache->type_tag,
-                                             arg_cache->transfer);
+                                             arg_cache->transfer,
+                                             cleanup_data);
 }
 
 gboolean
@@ -715,7 +725,8 @@ _pygi_marshal_from_py_array (PyGIInvokeState   *state,
                              PyGICallableCache *callable_cache,
                              PyGIArgCache      *arg_cache,
                              PyObject          *py_arg,
-                             GIArgument        *arg)
+                             GIArgument        *arg,
+                             gpointer          *cleanup_data)
 {
     PyGIMarshalFromPyFunc from_py_marshaller;
     int i = 0;
@@ -781,6 +792,7 @@ _pygi_marshal_from_py_array (PyGIInvokeState   *state,
     from_py_marshaller = sequence_cache->item_cache->from_py_marshaller;
     for (i = 0, success_count = 0; i < length; i++) {
         GIArgument item = {0};
+        gpointer item_cleanup_data = NULL;
         PyObject *py_item = PySequence_GetItem (py_arg, i);
         if (py_item == NULL)
             goto err;
@@ -789,12 +801,27 @@ _pygi_marshal_from_py_array (PyGIInvokeState   *state,
                                   callable_cache,
                                   sequence_cache->item_cache,
                                   py_item,
-                                 &item)) {
+                                 &item,
+                                 &item_cleanup_data)) {
             Py_DECREF (py_item);
             goto err;
         }
-
         Py_DECREF (py_item);
+
+        if (item_cleanup_data != NULL && item_cleanup_data != item.v_pointer) {
+            /* We only support one level of data discrepancy between an items
+             * data and its cleanup data. This is because we only track a single
+             * extra cleanup data pointer per-argument and cannot track the entire
+             * array of items differing data and cleanup_data.
+             * For example, this would fail if trying to marshal an array of
+             * callback closures marked with SCOPE call type where the cleanup data
+             * is different from the items v_pointer, likewise an array of arrays.
+             */
+            PyErr_SetString(PyExc_RuntimeError, "Cannot cleanup item data for array due to "
+                                                "the items data its cleanup data being different.");
+            goto err;
+        }
+
         /* FIXME: it is much more efficent to have seperate marshaller
          *        for ptr arrays than doing the evaluation
          *        and casting each loop iteration
@@ -826,6 +853,8 @@ _pygi_marshal_from_py_array (PyGIInvokeState   *state,
                             g_value_init (dest, G_VALUE_TYPE ((GValue*) item.v_pointer));
                             g_value_copy ((GValue*) item.v_pointer, dest);
                         }
+                        /* Manually increment the length because we are manually setting the memory. */
+                        array_->len++;
 
                     } else {
                         /* Handles flat arrays of boxed or struct types. */
@@ -837,7 +866,7 @@ _pygi_marshal_from_py_array (PyGIInvokeState   *state,
                      * due to "item" being a temporarily marshaled value done on the stack.
                      */
                     if (from_py_cleanup)
-                        from_py_cleanup (state, item_arg_cache, py_item, item.v_pointer, TRUE);
+                        from_py_cleanup (state, item_arg_cache, py_item, item_cleanup_data, TRUE);
 
                     break;
                 }
@@ -910,19 +939,16 @@ array_success:
 
     if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
         arg->v_pointer = array_->data;
-        g_array_free (array_, FALSE);
     } else {
         arg->v_pointer = array_;
     }
 
-    /* Store the allocated array in the arguments extra data for bi-directional
-     * marshaling cleanup. This is needed because arg->v_pointer will be
-     * clobbered by the caller and we would have no way to clean it up later.
-     * TODO: This should go in the outer layer and apply generically at some point.
+    /* In all cases give the array object back as cleanup data.
+     * In the case of GI_ARRAY_C, we give the data directly as the argument
+     * but keep the array_ wrapper as cleanup data so we don't have to find
+     * it's length again.
      */
-    if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
-        state->args_data[arg_cache->c_arg_index] = arg->v_pointer;
-    }
+    *cleanup_data = array_;
 
     return TRUE;
 }
@@ -932,7 +958,8 @@ _pygi_marshal_from_py_glist (PyGIInvokeState   *state,
                              PyGICallableCache *callable_cache,
                              PyGIArgCache      *arg_cache,
                              PyObject          *py_arg,
-                             GIArgument        *arg)
+                             GIArgument        *arg,
+                             gpointer          *cleanup_data)
 {
     PyGIMarshalFromPyFunc from_py_marshaller;
     int i;
@@ -966,7 +993,8 @@ _pygi_marshal_from_py_glist (PyGIInvokeState   *state,
 
     from_py_marshaller = sequence_cache->item_cache->from_py_marshaller;
     for (i = 0; i < length; i++) {
-        GIArgument item;
+        GIArgument item = {0};
+        gpointer item_cleanup_data = NULL;
         PyObject *py_item = PySequence_GetItem (py_arg, i);
         if (py_item == NULL)
             goto err;
@@ -975,7 +1003,8 @@ _pygi_marshal_from_py_glist (PyGIInvokeState   *state,
                                   callable_cache,
                                   sequence_cache->item_cache,
                                   py_item,
-                                 &item))
+                                 &item,
+                                 &item_cleanup_data))
             goto err;
 
         Py_DECREF (py_item);
@@ -994,6 +1023,7 @@ err:
     }
 
     arg->v_pointer = g_list_reverse (list_);
+    *cleanup_data = arg->v_pointer;
     return TRUE;
 }
 
@@ -1002,7 +1032,8 @@ _pygi_marshal_from_py_gslist (PyGIInvokeState   *state,
                               PyGICallableCache *callable_cache,
                               PyGIArgCache      *arg_cache,
                               PyObject          *py_arg,
-                              GIArgument        *arg)
+                              GIArgument        *arg,
+                              gpointer          *cleanup_data)
 {
     PyGIMarshalFromPyFunc from_py_marshaller;
     int i;
@@ -1035,7 +1066,8 @@ _pygi_marshal_from_py_gslist (PyGIInvokeState   *state,
 
     from_py_marshaller = sequence_cache->item_cache->from_py_marshaller;
     for (i = 0; i < length; i++) {
-        GIArgument item;
+        GIArgument item = {0};
+        gpointer item_cleanup_data = NULL;
         PyObject *py_item = PySequence_GetItem (py_arg, i);
         if (py_item == NULL)
             goto err;
@@ -1044,7 +1076,8 @@ _pygi_marshal_from_py_gslist (PyGIInvokeState   *state,
                              callable_cache,
                              sequence_cache->item_cache,
                              py_item,
-                            &item))
+                            &item,
+                            &item_cleanup_data))
             goto err;
 
         Py_DECREF (py_item);
@@ -1064,6 +1097,7 @@ err:
     }
 
     arg->v_pointer = g_slist_reverse (list_);
+    *cleanup_data = arg->v_pointer;
     return TRUE;
 }
 
@@ -1072,7 +1106,8 @@ _pygi_marshal_from_py_ghash (PyGIInvokeState   *state,
                              PyGICallableCache *callable_cache,
                              PyGIArgCache      *arg_cache,
                              PyObject          *py_arg,
-                             GIArgument        *arg)
+                             GIArgument        *arg,
+                             gpointer          *cleanup_data)
 {
     PyGIMarshalFromPyFunc key_from_py_marshaller;
     PyGIMarshalFromPyFunc value_from_py_marshaller;
@@ -1135,6 +1170,8 @@ _pygi_marshal_from_py_ghash (PyGIInvokeState   *state,
 
     for (i = 0; i < length; i++) {
         GIArgument key, value;
+        gpointer key_cleanup_data = NULL;
+        gpointer value_cleanup_data = NULL;
         PyObject *py_key = PyList_GET_ITEM (py_keys, i);
         PyObject *py_value = PyList_GET_ITEM (py_values, i);
         if (py_key == NULL || py_value == NULL)
@@ -1144,14 +1181,16 @@ _pygi_marshal_from_py_ghash (PyGIInvokeState   *state,
                                       callable_cache,
                                       hash_cache->key_cache,
                                       py_key,
-                                     &key))
+                                     &key,
+                                     &key_cleanup_data))
             goto err;
 
         if (!value_from_py_marshaller ( state,
                                         callable_cache,
                                         hash_cache->value_cache,
                                         py_value,
-                                       &value))
+                                       &value,
+                                       &value_cleanup_data))
             goto err;
 
         g_hash_table_insert (hash_,
@@ -1170,6 +1209,7 @@ err:
     }
 
     arg->v_pointer = hash_;
+    *cleanup_data = arg->v_pointer;
     return TRUE;
 }
 
@@ -1178,7 +1218,8 @@ _pygi_marshal_from_py_gerror (PyGIInvokeState   *state,
                               PyGICallableCache *callable_cache,
                               PyGIArgCache      *arg_cache,
                               PyObject          *py_arg,
-                              GIArgument        *arg)
+                              GIArgument        *arg,
+                              gpointer          *cleanup_data)
 {
     PyErr_Format (PyExc_NotImplementedError,
                   "Marshalling for GErrors is not implemented");
@@ -1244,7 +1285,8 @@ _pygi_marshal_from_py_interface_callback (PyGIInvokeState   *state,
                                           PyGICallableCache *callable_cache,
                                           PyGIArgCache      *arg_cache,
                                           PyObject          *py_arg,
-                                          GIArgument        *arg)
+                                          GIArgument        *arg,
+                                          gpointer          *cleanup_data)
 {
     GICallableInfo *callable_info;
     PyGICClosure *closure;
@@ -1331,10 +1373,8 @@ _pygi_marshal_from_py_interface_callback (PyGIInvokeState   *state,
         }
     }
 
-    /* Store the PyGIClosure as extra args data so _pygi_marshal_cleanup_from_py_interface_callback
-     * can clean it up later for GI_SCOPE_TYPE_CALL based closures.
-     */
-    state->args_data[arg_cache->c_arg_index] = closure;
+    /* Use the PyGIClosure as data passed to cleanup for GI_SCOPE_TYPE_CALL. */
+    *cleanup_data = closure;
 
     return TRUE;
 }
@@ -1344,7 +1384,8 @@ _pygi_marshal_from_py_interface_enum (PyGIInvokeState   *state,
                                       PyGICallableCache *callable_cache,
                                       PyGIArgCache      *arg_cache,
                                       PyObject          *py_arg,
-                                      GIArgument        *arg)
+                                      GIArgument        *arg,
+                                      gpointer          *cleanup_data)
 {
     PyObject *py_long;
     long c_long;
@@ -1412,7 +1453,8 @@ _pygi_marshal_from_py_interface_flags (PyGIInvokeState   *state,
                                        PyGICallableCache *callable_cache,
                                        PyGIArgCache      *arg_cache,
                                        PyObject          *py_arg,
-                                       GIArgument        *arg)
+                                       GIArgument        *arg,
+                                       gpointer          *cleanup_data)
 {
     PyObject *py_long;
     long c_long;
@@ -1459,20 +1501,27 @@ _pygi_marshal_from_py_interface_struct_cache_adapter (PyGIInvokeState   *state,
                                                       PyGICallableCache *callable_cache,
                                                       PyGIArgCache      *arg_cache,
                                                       PyObject          *py_arg,
-                                                      GIArgument        *arg)
+                                                      GIArgument        *arg,
+                                                      gpointer          *cleanup_data)
 {
     PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
 
-    return _pygi_marshal_from_py_interface_struct (py_arg,
-                                                   arg,
-                                                   arg_cache->arg_name,
-                                                   iface_cache->interface_info,
-                                                   iface_cache->g_type,
-                                                   iface_cache->py_type,
-                                                   arg_cache->transfer,
-                                                   TRUE, /*copy_reference*/
-                                                   iface_cache->is_foreign,
-                                                   arg_cache->is_pointer);
+    gboolean res =  _pygi_marshal_from_py_interface_struct (py_arg,
+                                                            arg,
+                                                            arg_cache->arg_name,
+                                                            iface_cache->interface_info,
+                                                            iface_cache->g_type,
+                                                            iface_cache->py_type,
+                                                            arg_cache->transfer,
+                                                            TRUE, /*copy_reference*/
+                                                            iface_cache->is_foreign,
+                                                            arg_cache->is_pointer);
+
+    /* Assume struct marshaling is always a pointer and assign cleanup_data
+     * here rather than passing it further down the chain.
+     */
+    *cleanup_data = arg->v_pointer;
+    return res;
 }
 
 gboolean
@@ -1480,7 +1529,8 @@ _pygi_marshal_from_py_interface_boxed (PyGIInvokeState   *state,
                                        PyGICallableCache *callable_cache,
                                        PyGIArgCache      *arg_cache,
                                        PyObject          *py_arg,
-                                       GIArgument        *arg)
+                                       GIArgument        *arg,
+                                       gpointer          *cleanup_data)
 {
     PyErr_Format (PyExc_NotImplementedError,
                   "Marshalling for this type is not implemented yet");
@@ -1492,8 +1542,11 @@ _pygi_marshal_from_py_interface_object (PyGIInvokeState   *state,
                                         PyGICallableCache *callable_cache,
                                         PyGIArgCache      *arg_cache,
                                         PyObject          *py_arg,
-                                        GIArgument        *arg)
+                                        GIArgument        *arg,
+                                        gpointer          *cleanup_data)
 {
+    gboolean res = FALSE;
+
     if (py_arg == Py_None) {
         arg->v_pointer = NULL;
         return TRUE;
@@ -1513,7 +1566,9 @@ _pygi_marshal_from_py_interface_object (PyGIInvokeState   *state,
         return FALSE;
     }
 
-    return _pygi_marshal_from_py_gobject (py_arg, arg, arg_cache->transfer);
+    res = _pygi_marshal_from_py_gobject (py_arg, arg, arg_cache->transfer);
+    *cleanup_data = arg->v_pointer;
+    return res;
 }
 
 gboolean
@@ -1521,7 +1576,8 @@ _pygi_marshal_from_py_interface_union (PyGIInvokeState   *state,
                                        PyGICallableCache *callable_cache,
                                        PyGIArgCache      *arg_cache,
                                        PyObject          *py_arg,
-                                       GIArgument        *arg)
+                                       GIArgument        *arg,
+                                       gpointer          *cleanup_data)
 {
     PyErr_Format(PyExc_NotImplementedError,
                  "Marshalling for this type is not implemented yet");
diff --git a/gi/pygi-marshal-from-py.h b/gi/pygi-marshal-from-py.h
index e8b9031..f8e4699 100644
--- a/gi/pygi-marshal-from-py.h
+++ b/gi/pygi-marshal-from-py.h
@@ -37,78 +37,93 @@ gboolean _pygi_marshal_from_py_void        (PyGIInvokeState   *state,
                                             PyGICallableCache *callable_cache,
                                             PyGIArgCache      *arg_cache,
                                             PyObject          *py_arg,
-                                            GIArgument        *arg);
+                                            GIArgument        *arg,
+                                            gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_array       (PyGIInvokeState   *state,
                                             PyGICallableCache *callable_cache,
                                             PyGIArgCache      *arg_cache,
                                             PyObject          *py_arg,
-                                            GIArgument        *arg);
+                                            GIArgument        *arg,
+                                            gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_glist       (PyGIInvokeState   *state,
                                             PyGICallableCache *callable_cache,
                                             PyGIArgCache      *arg_cache,
                                             PyObject          *py_arg,
-                                            GIArgument        *arg);
+                                            GIArgument        *arg,
+                                            gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_gslist      (PyGIInvokeState   *state,
                                             PyGICallableCache *callable_cache,
                                             PyGIArgCache      *arg_cache,
                                             PyObject          *py_arg,
-                                            GIArgument        *arg);
+                                            GIArgument        *arg,
+                                            gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_ghash       (PyGIInvokeState   *state,
                                             PyGICallableCache *callable_cache,
                                             PyGIArgCache      *arg_cache,
                                             PyObject          *py_arg,
-                                            GIArgument        *arg);
+                                            GIArgument        *arg,
+                                            gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_gerror      (PyGIInvokeState   *state,
                                             PyGICallableCache *callable_cache,
                                             PyGIArgCache      *arg_cache,
                                             PyObject          *py_arg,
-                                            GIArgument        *arg);
+                                            GIArgument        *arg,
+                                            gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_interface_callback (PyGIInvokeState   *state,
                                                    PyGICallableCache *callable_cache,
                                                    PyGIArgCache      *arg_cache,
                                                    PyObject          *py_arg,
-                                                   GIArgument        *arg);
+                                                   GIArgument        *arg,
+                                                   gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_interface_enum     (PyGIInvokeState   *state,
                                                    PyGICallableCache *callable_cache,
                                                    PyGIArgCache      *arg_cache,
                                                    PyObject          *py_arg,
-                                                   GIArgument        *arg);
+                                                   GIArgument        *arg,
+                                                   gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_interface_flags    (PyGIInvokeState   *state,
                                                    PyGICallableCache *callable_cache,
                                                    PyGIArgCache      *arg_cache,
                                                    PyObject          *py_arg,
-                                                   GIArgument        *arg);
+                                                   GIArgument        *arg,
+                                                   gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_interface_struct_cache_adapter   (PyGIInvokeState   *state,
                                                                  PyGICallableCache *callable_cache,
                                                                  PyGIArgCache      *arg_cache,
                                                                  PyObject          *py_arg,
-                                                                 GIArgument        *arg);
+                                                                 GIArgument        *arg,
+                                                                 gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_interface_boxed    (PyGIInvokeState   *state,
                                                    PyGICallableCache *callable_cache,
                                                    PyGIArgCache      *arg_cache,
                                                    PyObject          *py_arg,
-                                                   GIArgument        *arg);
+                                                   GIArgument        *arg,
+                                                   gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_interface_object   (PyGIInvokeState   *state,
                                                    PyGICallableCache *callable_cache,
                                                    PyGIArgCache      *arg_cache,
                                                    PyObject          *py_arg,
-                                                   GIArgument        *arg);
+                                                   GIArgument        *arg,
+                                                   gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_interface_union    (PyGIInvokeState   *state,
                                                    PyGICallableCache *callable_cache,
                                                    PyGIArgCache      *arg_cache,
                                                    PyObject          *py_arg,
-                                                   GIArgument        *arg);
+                                                   GIArgument        *arg,
+                                                   gpointer          *cleanup_data);
 
 /* Simplified marshalers shared between vfunc/closure and direct function calls. */
 gboolean _pygi_marshal_from_py_basic_type (PyObject   *object,   /* in */
                                            GIArgument *arg,      /* out */
                                            GITypeTag   type_tag,
-                                           GITransfer  transfer);
+                                           GITransfer  transfer,
+                                           gpointer   *cleanup_data);
 gboolean _pygi_marshal_from_py_basic_type_cache_adapter  (PyGIInvokeState   *state,
                                                           PyGICallableCache *callable_cache,
                                                           PyGIArgCache      *arg_cache,
                                                           PyObject          *py_arg,
-                                                          GIArgument        *arg);
+                                                          GIArgument        *arg,
+                                                          gpointer          *cleanup_data);
 
 gboolean _pygi_marshal_from_py_gobject (PyObject *py_arg, /*in*/
                                         GIArgument *arg,  /*out*/



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