summaryrefslogtreecommitdiff
path: root/gi/pygi-invoke.c
diff options
context:
space:
mode:
Diffstat (limited to 'gi/pygi-invoke.c')
-rw-r--r--gi/pygi-invoke.c333
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;
}