[pygobject] make sure caller allocated structs are freed when they go out of scope



commit c9da5782e6c633d9af43ee85075e9ee65db09780
Author: John (J5) Palmieri <johnp redhat com>
Date:   Fri Jul 9 13:14:42 2010 -0400

    make sure caller allocated structs are freed when they go out of scope
    
    * Move struct transfer checks from pygi-arguments to pygi-invoke
    * add better warning if an unknown struct is fully transfered
    * only free GValues we create in the invoke cleanup.  All other structs
      get cleaned up when they go out of scope in python
    * Fixes issues with caller allocated treeiters getting freed to early
    * this is a fix to crashes in the current test suite when API's returning
      TreeIters were annotated as out caller-allocates so no new tests
      are needed
    
    https://bugzilla.gnome.org/show_bug.cgi?id=623969

 gi/pygi-argument.c |   13 +++++--------
 gi/pygi-invoke.c   |   46 ++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 45 insertions(+), 14 deletions(-)
---
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index 24f996e..6bea63f 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -1368,15 +1368,12 @@ _pygi_argument_to_object (GArgument  *arg,
                             break;
                         }
 
-                        if (transfer != GI_TRANSFER_NOTHING)
-                            g_warning ("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.");
-
+                        /* Only structs created in invoke can be safely marked
+                         * GI_TRANSFER_EVERYTHING. Trust that invoke has
+                         * filtered correctly
+                         */
                         object = _pygi_struct_new ( (PyTypeObject *) py_type, arg->v_pointer,
-                                                    FALSE);
+                                                    transfer == GI_TRANSFER_EVERYTHING);
 
                         Py_DECREF (py_type);
                     } else {
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c
index 022874e..2bd1978 100644
--- a/gi/pygi-invoke.c
+++ b/gi/pygi-invoke.c
@@ -675,11 +675,14 @@ _process_invocation_state (struct invocation_state *state,
                             state->return_type_info, state->return_arg.v_pointer);
                 } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
                     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 {
@@ -795,6 +798,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 %u 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. */
@@ -923,15 +956,16 @@ _free_invocation_state (struct invocation_state *state)
 
             /* 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
+             * as caller-allocates
              */
             if (info_type == GI_INFO_TYPE_STRUCT) {
-                /* special case GValues so we make sure to unset them */
+                /* special case GValues since all other structs are returned
+                 * as is and freed when they go out of scope
+                 */
                 if (g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info) == G_TYPE_VALUE) {
                     g_value_unset ( (GValue *) state->args[i]);
+                    g_free (state->args[i]);
                 }
-
-                g_free (state->args[i]);
             }
         }
 



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