Commit 7407367f authored by Simon Feltman's avatar Simon Feltman
Browse files

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
parent 9456e832
......@@ -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;
}
......
......@@ -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,
......
......@@ -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
......
......@@ -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:
......
......@@ -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) {
......
This diff is collapsed.
......@@ -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*/
......
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