gdkwindow: Handle references in "update_windows" list correctly

Since update_windows list is a static variable in GdkWindow.c which
contains pointers to windows which needs to be updated, it can happen
that it contains a pointer to a window even after quit from a gtk_main().
If another gtk_main() is called in the same process it tries to process
windows in the list which leads to a crash.
Correct reference count handling of added windows prevents such applications
from crash.

https://bugzilla.gnome.org/show_bug.cgi?id=711552
This commit is contained in:
Marek Kasik 2013-12-12 15:02:19 +01:00
parent bfd27445e6
commit 1b032b18cc

View File

@ -3252,7 +3252,7 @@ gdk_window_add_update_window (GdkWindow *window)
prev = tmp; prev = tmp;
} }
/* here, tmp got advanced past all lower stacked siblings */ /* here, tmp got advanced past all lower stacked siblings */
tmp = g_slist_prepend (tmp, window); tmp = g_slist_prepend (tmp, g_object_ref (window));
if (prev) if (prev)
prev->next = tmp; prev->next = tmp;
else else
@ -3265,7 +3265,7 @@ gdk_window_add_update_window (GdkWindow *window)
*/ */
if (has_ancestor_in_list && gdk_window_is_ancestor (tmp->data, window)) if (has_ancestor_in_list && gdk_window_is_ancestor (tmp->data, window))
{ {
tmp = g_slist_prepend (tmp, window); tmp = g_slist_prepend (tmp, g_object_ref (window));
if (prev) if (prev)
prev->next = tmp; prev->next = tmp;
@ -3279,7 +3279,7 @@ gdk_window_add_update_window (GdkWindow *window)
*/ */
if (! tmp->next && has_ancestor_in_list) if (! tmp->next && has_ancestor_in_list)
{ {
tmp = g_slist_append (tmp, window); tmp = g_slist_append (tmp, g_object_ref (window));
return; return;
} }
@ -3290,13 +3290,20 @@ gdk_window_add_update_window (GdkWindow *window)
* hierarchy than what is already in the list) or the list is * hierarchy than what is already in the list) or the list is
* empty, prepend * empty, prepend
*/ */
update_windows = g_slist_prepend (update_windows, window); update_windows = g_slist_prepend (update_windows, g_object_ref (window));
} }
static void static void
gdk_window_remove_update_window (GdkWindow *window) gdk_window_remove_update_window (GdkWindow *window)
{ {
update_windows = g_slist_remove (update_windows, window); GSList *link;
link = g_slist_find (update_windows, window);
if (link != NULL)
{
update_windows = g_slist_delete_link (update_windows, link);
g_object_unref (window);
}
} }
static gboolean static gboolean
@ -3579,8 +3586,6 @@ gdk_window_process_all_updates (void)
before_process_all_updates (); before_process_all_updates ();
g_slist_foreach (old_update_windows, (GFunc)g_object_ref, NULL);
while (tmp_list) while (tmp_list)
{ {
GdkWindow *window = tmp_list->data; GdkWindow *window = tmp_list->data;