diff options
Diffstat (limited to 'gi/pygi-invoke.c')
-rw-r--r-- | gi/pygi-invoke.c | 333 |
1 files changed, 124 insertions, 209 deletions
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c index a470003..64b3f31 100644 --- a/gi/pygi-invoke.c +++ b/gi/pygi-invoke.c @@ -49,14 +49,14 @@ struct invocation_state GITypeInfo *return_type_info; GITypeTag return_type_tag; - GArgument **args; + GIArgument **args; gboolean *args_is_auxiliary; - GArgument *in_args; - GArgument *out_args; - GArgument *out_values; - GArgument *backup_args; - GArgument return_arg; + GIArgument *in_args; + GIArgument *out_args; + GIArgument *out_values; + GIArgument *backup_args; + GIArgument return_arg; PyObject *return_value; }; @@ -154,18 +154,14 @@ _prepare_invocation_state (struct invocation_state *state, if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) { state->n_in_args += 1; - if (transfer == GI_TRANSFER_CONTAINER) { - state->n_backup_args += 1; - } + } + if (direction == GI_DIRECTION_INOUT) { + state->n_backup_args += 1; } if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) { state->n_out_args += 1; } - if (direction == GI_DIRECTION_INOUT && transfer == GI_TRANSFER_NOTHING) { - state->n_backup_args += 1; - } - switch (arg_type_tag) { case GI_TYPE_TAG_ARRAY: { @@ -173,13 +169,16 @@ _prepare_invocation_state (struct invocation_state *state, length_arg_pos = g_type_info_get_array_length (state->arg_type_infos[i]); - if (state->is_method) - length_arg_pos--; // length_arg_pos refers to C args - if (length_arg_pos < 0) { break; } + /* For array lengths, we're going to delete the length argument; + * so remove the extra backup we just added above */ + if (direction == GI_DIRECTION_INOUT) { + state->n_backup_args -= 1; + } + g_assert (length_arg_pos < state->n_args); state->args_is_auxiliary[length_arg_pos] = TRUE; @@ -208,9 +207,6 @@ _prepare_invocation_state (struct invocation_state *state, gint length_arg_pos; length_arg_pos = g_type_info_get_array_length (state->return_type_info); - if (state->is_method) - length_arg_pos--; // length_arg_pos refers to C args - if (length_arg_pos >= 0) { g_assert (length_arg_pos < state->n_args); state->args_is_auxiliary[length_arg_pos] = TRUE; @@ -285,10 +281,10 @@ _prepare_invocation_state (struct invocation_state *state, } state->args = g_slice_alloc0 (sizeof (gpointer) * state->n_args); - state->in_args = g_slice_alloc0 (sizeof (GArgument) * state->n_in_args); - state->out_args = g_slice_alloc0 (sizeof (GArgument) * state->n_out_args); - state->out_values = g_slice_alloc0 (sizeof (GArgument) * state->n_out_args); - state->backup_args = g_slice_alloc0 (sizeof (GArgument) * state->n_backup_args); + state->in_args = g_slice_alloc0 (sizeof (GIArgument) * state->n_in_args); + state->out_args = g_slice_alloc0 (sizeof (GIArgument) * state->n_out_args); + state->out_values = g_slice_alloc0 (sizeof (GIArgument) * state->n_out_args); + state->backup_args = g_slice_alloc0 (sizeof (GIArgument) * state->n_backup_args); /* Bind args so we can use an unique index. */ { @@ -344,19 +340,15 @@ _prepare_invocation_state (struct invocation_state *state, } if (is_caller_allocates) { - gsize size; - /* if caller allocates only use one level of indirection */ state->out_args[out_args_pos].v_pointer = NULL; state->args[i] = &state->out_args[out_args_pos]; - - /* FIXME: Remove when bgo#622711 is fixed */ - if (g_registered_type_info_get_g_type (info) == G_TYPE_VALUE) - size = sizeof (GValue); - else - size = g_struct_info_get_size ( (GIStructInfo *) info); - - state->args[i]->v_pointer = g_malloc0 (size); + if (g_type_is_a (g_registered_type_info_get_g_type (info), G_TYPE_BOXED)) + state->args[i]->v_pointer = _pygi_boxed_alloc (info, NULL); + else { + gssize size = g_struct_info_get_size ( (GIStructInfo *) info); + state->args[i]->v_pointer = g_malloc0 (size); + } } else { state->out_args[out_args_pos].v_pointer = &state->out_values[out_args_pos]; state->out_values[out_args_pos].v_pointer = NULL; @@ -387,6 +379,7 @@ _prepare_invocation_state (struct invocation_state *state, GIBaseInfo *container_info; GIInfoType container_info_type; PyObject *py_arg; + gint check_val; container_info = g_base_info_get_container (function_info); container_info_type = g_base_info_get_type (container_info); @@ -394,6 +387,19 @@ _prepare_invocation_state (struct invocation_state *state, g_assert (py_args_pos < state->n_py_args); py_arg = PyTuple_GET_ITEM (py_args, py_args_pos); + /* In python 2 python takes care of checking the type + * of the self instance. In python 3 it does not + * so we have to check it here + */ + check_val = _pygi_g_type_interface_check_object(container_info, + py_arg); + if (check_val < 0) { + return FALSE; + } else if (!check_val) { + _PyGI_ERROR_PREFIX ("instance: "); + return FALSE; + } + switch (container_info_type) { case GI_INFO_TYPE_UNION: case GI_INFO_TYPE_STRUCT: @@ -487,61 +493,11 @@ _prepare_invocation_state (struct invocation_state *state, return FALSE; } - if (direction == GI_DIRECTION_INOUT && transfer == GI_TRANSFER_NOTHING) { + if (direction == GI_DIRECTION_INOUT) { /* We need to keep a copy of the argument to be able to release it later. */ g_assert (backup_args_pos < state->n_backup_args); state->backup_args[backup_args_pos] = *state->args[i]; backup_args_pos += 1; - } else if (transfer == GI_TRANSFER_CONTAINER) { - /* We need to keep a copy of the items to be able to release them later. */ - switch (arg_type_tag) { - case GI_TYPE_TAG_ARRAY: - { - GArray *array; - gsize item_size; - GArray *new_array; - - array = state->args[i]->v_pointer; - - item_size = g_array_get_element_size (array); - - new_array = g_array_sized_new (FALSE, FALSE, item_size, array->len); - g_array_append_vals (new_array, array->data, array->len); - - g_assert (backup_args_pos < state->n_backup_args); - state->backup_args[backup_args_pos].v_pointer = new_array; - - break; - } - case GI_TYPE_TAG_GLIST: - g_assert (backup_args_pos < state->n_backup_args); - state->backup_args[backup_args_pos].v_pointer = g_list_copy (state->args[i]->v_pointer); - break; - case GI_TYPE_TAG_GSLIST: - g_assert (backup_args_pos < state->n_backup_args); - state->backup_args[backup_args_pos].v_pointer = g_slist_copy (state->args[i]->v_pointer); - break; - case GI_TYPE_TAG_GHASH: - { - GHashTable *hash_table; - GList *keys; - GList *values; - - hash_table = state->args[i]->v_pointer; - - keys = g_hash_table_get_keys (hash_table); - values = g_hash_table_get_values (hash_table); - - g_assert (backup_args_pos < state->n_backup_args); - state->backup_args[backup_args_pos].v_pointer = g_list_concat (keys, values); - - break; - } - default: - g_warn_if_reached(); - } - - backup_args_pos += 1; } if (arg_type_tag == GI_TYPE_TAG_ARRAY) { @@ -551,8 +507,6 @@ _prepare_invocation_state (struct invocation_state *state, array = state->args[i]->v_pointer; length_arg_pos = g_type_info_get_array_length (state->arg_type_infos[i]); - if (state->is_method) - length_arg_pos--; // length_arg_pos refers to C args if (length_arg_pos >= 0) { int len = 0; /* Set the auxiliary argument holding the length. */ @@ -639,6 +593,11 @@ _process_invocation_state (struct invocation_state *state, GIInfoType info_type; GITransfer transfer; + if (state->return_arg.v_pointer == NULL) { + PyErr_SetString (PyExc_TypeError, "constructor returned NULL"); + return FALSE; + } + g_assert (state->n_py_args > 0); py_type = (PyTypeObject *) PyTuple_GET_ITEM (py_args, 0); @@ -651,10 +610,6 @@ _process_invocation_state (struct invocation_state *state, switch (info_type) { case GI_INFO_TYPE_UNION: - /* TODO */ - PyErr_SetString (PyExc_NotImplementedError, "creating unions is not supported yet"); - g_base_info_unref (info); - return FALSE; case GI_INFO_TYPE_STRUCT: { GType type; @@ -662,24 +617,22 @@ _process_invocation_state (struct invocation_state *state, type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); if (g_type_is_a (type, G_TYPE_BOXED)) { - if (state->return_arg.v_pointer == NULL) { - PyErr_SetString (PyExc_TypeError, "constructor returned NULL"); - break; - } g_warn_if_fail (transfer == GI_TRANSFER_EVERYTHING); state->return_value = _pygi_boxed_new (py_type, state->return_arg.v_pointer, transfer == GI_TRANSFER_EVERYTHING); + } else if (type == G_TYPE_NONE && g_struct_info_is_foreign (info)) { + state->return_value = + pygi_struct_foreign_convert_from_g_argument ( + state->return_type_info, state->return_arg.v_pointer); } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) { - if (state->return_arg.v_pointer == NULL) { - PyErr_SetString (PyExc_TypeError, "constructor returned NULL"); - break; - } - if (transfer != GI_TRANSFER_NOTHING) - g_warning ("Transfer mode should be set to None for " + g_warning ("Return argument in %s returns a struct " + "with a transfer mode of \"full\" " + "Transfer mode should be set to None for " "struct types as there is no way to free " "them safely. Ignoring transfer mode " "to prevent a potential invalid free. " - "This may cause a leak in your application."); + "This may cause a leak in your application.", + g_base_info_get_name ( (GIBaseInfo *) function_info) ); state->return_value = _pygi_struct_new (py_type, state->return_arg.v_pointer, FALSE); } else { @@ -740,10 +693,8 @@ _process_invocation_state (struct invocation_state *state, /* Convert output arguments and release arguments. */ { - gsize backup_args_pos; gsize return_values_pos; - backup_args_pos = 0; return_values_pos = 0; if (state->n_return_values > 1) { @@ -795,6 +746,36 @@ _process_invocation_state (struct invocation_state *state, /* Convert the argument. */ PyObject *obj; + /* If we created it, deallocate when it goes out of scope + * otherwise it is unsafe to deallocate random structures + * we are given + */ + if (type_tag == GI_TYPE_TAG_INTERFACE) { + GIBaseInfo *info; + GIInfoType info_type; + + info = g_type_info_get_interface (state->arg_type_infos[i]); + g_assert (info != NULL); + info_type = g_base_info_get_type (info); + + if ( (info_type == GI_INFO_TYPE_STRUCT) && + !g_struct_info_is_foreign((GIStructInfo *) info) ) { + if (g_arg_info_is_caller_allocates (state->arg_infos[i])) { + transfer = GI_TRANSFER_EVERYTHING; + } else if (transfer == GI_TRANSFER_EVERYTHING) { + transfer = GI_TRANSFER_NOTHING; + g_warning ("Out argument %ld in %s returns a struct " + "with a transfer mode of \"full\". " + "Transfer mode should be set to \"none\" for " + "struct type returns as there is no way to free " + "them safely. Ignoring transfer mode " + "to prevent a potential invalid free. " + "This may cause a leak in your application.", + i, g_base_info_get_name ( (GIBaseInfo *) function_info) ); + } + } + } + obj = _pygi_argument_to_object (state->args[i], state->arg_type_infos[i], transfer); if (obj == NULL) { /* TODO: release arguments. */ @@ -814,83 +795,9 @@ _process_invocation_state (struct invocation_state *state, return_values_pos += 1; } - /* Release the argument. */ - - if ( (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) - && transfer == GI_TRANSFER_CONTAINER) { - /* Release the items we kept in another container. */ - switch (type_tag) { - case GI_TYPE_TAG_ARRAY: - case GI_TYPE_TAG_GLIST: - case GI_TYPE_TAG_GSLIST: - g_assert (backup_args_pos < state->n_backup_args); - _pygi_argument_release (&state->backup_args[backup_args_pos], state->arg_type_infos[i], - transfer, GI_DIRECTION_IN); - break; - case GI_TYPE_TAG_GHASH: - { - GITypeInfo *key_type_info; - GITypeInfo *value_type_info; - GList *item; - gsize length; - gsize j; - - key_type_info = g_type_info_get_param_type (state->arg_type_infos[i], 0); - value_type_info = g_type_info_get_param_type (state->arg_type_infos[i], 1); - - g_assert (backup_args_pos < state->n_backup_args); - item = state->backup_args[backup_args_pos].v_pointer; - - length = g_list_length (item) / 2; - - for (j = 0; j < length; j++, item = g_list_next (item)) { - _pygi_argument_release ( (GArgument *) &item->data, key_type_info, - GI_TRANSFER_NOTHING, GI_DIRECTION_IN); - } - - for (j = 0; j < length; j++, item = g_list_next (item)) { - _pygi_argument_release ( (GArgument *) &item->data, value_type_info, - GI_TRANSFER_NOTHING, GI_DIRECTION_IN); - } - - g_list_free (state->backup_args[backup_args_pos].v_pointer); - - break; - } - default: - g_warn_if_reached(); - } - - if (direction == GI_DIRECTION_INOUT) { - /* Release the output argument. */ - _pygi_argument_release (state->args[i], state->arg_type_infos[i], GI_TRANSFER_CONTAINER, - GI_DIRECTION_OUT); - } - - backup_args_pos += 1; - } else if (direction == GI_DIRECTION_INOUT) { - if (transfer == GI_TRANSFER_NOTHING) { - g_assert (backup_args_pos < state->n_backup_args); - _pygi_argument_release (&state->backup_args[backup_args_pos], state->arg_type_infos[i], - GI_TRANSFER_NOTHING, GI_DIRECTION_IN); - backup_args_pos += 1; - } - - _pygi_argument_release (state->args[i], state->arg_type_infos[i], transfer, - GI_DIRECTION_OUT); - } else { - _pygi_argument_release (state->args[i], state->arg_type_infos[i], transfer, direction); - } - - if (type_tag == GI_TYPE_TAG_ARRAY - && (direction != GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)) { - /* We created a #GArray and it has not been released above, so free it. */ - state->args[i]->v_pointer = g_array_free (state->args[i]->v_pointer, FALSE); - } } g_assert (state->n_return_values <= 1 || return_values_pos == state->n_return_values); - g_assert (backup_args_pos == state->n_backup_args); } return TRUE; @@ -900,6 +807,7 @@ static void _free_invocation_state (struct invocation_state *state) { gsize i; + gsize backup_args_pos; if (state->return_type_info != NULL) { g_base_info_unref ( (GIBaseInfo *) state->return_type_info); @@ -910,29 +818,42 @@ _free_invocation_state (struct invocation_state *state) _pygi_invoke_closure_free (state->closure); } + /* release all arguments. */ + backup_args_pos = 0; for (i = 0; i < state->n_args; i++) { - /* check for caller-allocated values we need to free */ - if (g_arg_info_is_caller_allocates (state->arg_infos[i])) { - GIBaseInfo *info; - GIInfoType info_type; + if (state->args_is_auxiliary[i]) { + /* Auxiliary arguments are not released. */ + continue; + } - info = g_type_info_get_interface (state->arg_type_infos[i]); - g_assert (info != NULL); - info_type = g_base_info_get_type (info); + if (state->args != NULL + && state->args[i] != NULL + && state->arg_infos[i] != NULL + && state->arg_type_infos[i] != NULL) { + GIDirection direction; + GITypeTag type_tag; + GITransfer transfer; - /* caller-allocates applies only to structs right now - * the GI scanner is overzealous when marking parameters - * as caller-allocates, so we only free if this was a struct - */ - if (info_type == GI_INFO_TYPE_STRUCT) { - /* special case GValues so we make sure to unset them */ - if (g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info) == G_TYPE_VALUE) { - g_value_unset ( (GValue *) state->args[i]); - } + direction = g_arg_info_get_direction (state->arg_infos[i]); + transfer = g_arg_info_get_ownership_transfer (state->arg_infos[i]); + + type_tag = g_type_info_get_tag (state->arg_type_infos[i]); + + /* Release the argument. */ + if (direction == GI_DIRECTION_INOUT) { + _pygi_argument_release (&state->backup_args[backup_args_pos], state->arg_type_infos[i], + transfer, GI_DIRECTION_IN); + backup_args_pos += 1; + } + _pygi_argument_release (state->args[i], state->arg_type_infos[i], transfer, direction); - g_free (state->args[i]); + if (type_tag == GI_TYPE_TAG_ARRAY + && (direction != GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)) { + /* We created a #GArray and it has not been released above, so free it. */ + state->args[i]->v_pointer = g_array_free (state->args[i]->v_pointer, FALSE); } + } if (state->arg_type_infos[i] != NULL) @@ -940,37 +861,30 @@ _free_invocation_state (struct invocation_state *state) if (state->arg_infos[i] != NULL) g_base_info_unref ( (GIBaseInfo *) state->arg_infos[i]); } + g_assert (backup_args_pos == state->n_backup_args); - if (state->arg_infos != NULL) { - g_slice_free1 (sizeof (gpointer) * state->n_args, state->arg_infos); - } - - if (state->arg_type_infos != NULL) { - g_slice_free1 (sizeof (gpointer) * state->n_args, state->arg_type_infos); - } + g_slice_free1 (sizeof (gpointer) * state->n_args, state->arg_infos); + g_slice_free1 (sizeof (gpointer) * state->n_args, state->arg_type_infos); + g_slice_free1 (sizeof (gboolean) * state->n_args, state->args_is_auxiliary); if (state->args != NULL) { g_slice_free1 (sizeof (gpointer) * state->n_args, state->args); } - if (state->args_is_auxiliary != NULL) { - g_slice_free1 (sizeof (gboolean) * state->n_args, state->args_is_auxiliary); - } - if (state->in_args != NULL) { - g_slice_free1 (sizeof (GArgument) * state->n_in_args, state->in_args); + g_slice_free1 (sizeof (GIArgument) * state->n_in_args, state->in_args); } if (state->out_args != NULL) { - g_slice_free1 (sizeof (GArgument) * state->n_out_args, state->out_args); + g_slice_free1 (sizeof (GIArgument) * state->n_out_args, state->out_args); } if (state->out_values != NULL) { - g_slice_free1 (sizeof (GArgument) * state->n_out_args, state->out_values); + g_slice_free1 (sizeof (GIArgument) * state->n_out_args, state->out_values); } if (state->backup_args != NULL) { - g_slice_free1 (sizeof (GArgument) * state->n_backup_args, state->backup_args); + g_slice_free1 (sizeof (GIArgument) * state->n_backup_args, state->backup_args); } if (PyErr_Occurred()) { @@ -1001,6 +915,7 @@ _wrap_g_function_info_invoke (PyGIBaseInfo *self, PyObject *py_args) return NULL; } + _free_invocation_state (&state); return state.return_value; } |