Re: Problems with un-owned objects passed to closures in pygobject (gtk_cell_renderer_text_start_editing)



2013/1/17 Simon Feltman <s feltman gmail com>:
> Hi Everyone,
>
> I'm trying to figure out a complete solution for proper reference management
> of gobjects passed into python vfuncs and signal closures as "in" arguments.
> Currently pygobject will add a ref to gobject arguments marked as
> transfer-none during marshaling and additionally sink/ref the gobject when
> the python object wrapper is created around it. The initial added ref during
> marshaling is then leaked upon the closure finishing in most cases.
>
> The fix could simply be to not add the initial ref during marshaling (or we
> need to make sure it is released when the closure finishes). The problem is
> this behavior is relied upon when a floating ref is passed and is the
> explicit fix described in the following ticket (which un-fortunately causes
> a leak in the non-floating case):
> https://bugzilla.gnome.org/show_bug.cgi?id=661359
>
> The specific problem described in bug 661359 occurs when a python closure is
> connected to a GtkCellRendererTexts "editing-started" signal. During the
> start of editing, a GtkEntry is created and passed almost immediately to
> signal emission before any ownership takes place:
> http://git.gnome.org/browse/gtk+/tree/gtk/gtkcellrenderer.c#n864
>
> This results in the following ref counting behavior of the GtkEntry as it is
> used by gtk_cell_area_activate_cell and gtk_cell_renderer_start_editing:
>
> 1 (floating) - gtk_cell_renderer_text_start_editing creates the GtkEntry
> 2 (floating) - g_signal_emit argument marshaling adds an additional ref
> during signal emission
> 3 (floating) - python closure marshaling adds an additional ref described
> above
> 3 (owned) - A PyGObject wraps the GtkEntry and sinks the floating ref
> * python callback is called and passed the wrapper
> 2 (owned) - The PyGObject wrapper is destroyed after the python callback
> finishes additionally freeing a gobject ref
> 1 (owned) - g_signal_emit argument marshaling completes and frees the ref it
> added
> 2 (owned) - gtk_cell_area_activate_cell sets the CellAreas edit widget which
> adds a ref
> 1 (owned) - cell editing finishes and removes the widget from the CellArea

I don't know the internals of pygobject, but to me it looks the leak
comes from not releasing the reference you add inside the callback
marshaller.
The way it works in gjs is:

1 (floating) - gtk_cell_renderer_text_start_editing creates the GtkEntry
2 (floating) - g_signal_emit argument marshaling adds an additional ref
during signal emission
2 (owned) - gjs closure marshaling creates a JS object wrapper,
calling ref_sink on the object
2 (owned, toggle, GC root) gjs adds a toggle reference and then
immediately unrefs the object
1 (owned, toggle, not rooted) - g_signal_emit argument marshaling
completes and frees the ref it added
2 (owned, toggle, GC root) - gtk_cell_area_activate_cell sets the
CellAreas edit widget which adds a ref
1 (owned, toggle, not rooted) - cell editing finishes and removes the
widget from the CellArea
... time passes ...
0 - GC triggers and the JS object finalizer removes the last ref

I know that Python doesn't have a GC in the traditional sense, but you
could still send finalization for GObject wrappers to a idle callback
so there is no risk of finalizing objects that C code assumes are
still alive.

Giovanni


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