diff -Nru gtk+2.0-2.24.10/debian/changelog gtk+2.0-2.24.10/debian/changelog --- gtk+2.0-2.24.10/debian/changelog 2014-02-06 19:22:45.000000000 +0400 +++ gtk+2.0-2.24.10/debian/changelog 2015-06-03 11:07:18.000000000 +0300 @@ -1,3 +1,16 @@ +gtk+2.0 (2.24.10-0ubuntu6.2) precise; urgency=low + + * Non-maintainer upload. + * fix_gdk_event_apply_filters.patch: new patch. Makes gdk_event_apply_filters + function safe against changes in the filter list, prevents weird crashes in + various apps. + * gdk-Fix-GdkWindowFilter-internal-refcounting.patch, + gdkwindow-Fix-event-unref-iteration.patch: new patches. Fix refcounting + errors after fix_gdk_event_apply_filters.patch, prevent crashes in some + applications like Spotify. + + -- Vlad Orlov Wed, 03 Jun 2015 11:04:37 +0300 + gtk+2.0 (2.24.10-0ubuntu6.1) precise; urgency=low * debian/patches/backport_search_printer_location.patch: diff -Nru gtk+2.0-2.24.10/debian/patches/fix_gdk_event_apply_filters.patch gtk+2.0-2.24.10/debian/patches/fix_gdk_event_apply_filters.patch --- gtk+2.0-2.24.10/debian/patches/fix_gdk_event_apply_filters.patch 1970-01-01 03:00:00.000000000 +0300 +++ gtk+2.0-2.24.10/debian/patches/fix_gdk_event_apply_filters.patch 2015-06-03 11:04:09.000000000 +0300 @@ -0,0 +1,319 @@ +Index: gtk+2.0-2.24.10/gdk/gdkinternals.h +=================================================================== +--- gtk+2.0-2.24.10.orig/gdk/gdkinternals.h 2011-12-20 22:32:29.000000000 +0400 ++++ gtk+2.0-2.24.10/gdk/gdkinternals.h 2015-06-03 11:04:06.731458219 +0300 +@@ -59,9 +59,15 @@ + guint ref_count; + }; + ++typedef enum { ++ GDK_EVENT_FILTER_REMOVED = 1 << 0 ++} GdkEventFilterFlags; ++ + struct _GdkEventFilter { + GdkFilterFunc function; + gpointer data; ++ GdkEventFilterFlags flags; ++ guint ref_count; + }; + + struct _GdkClientFilter { +Index: gtk+2.0-2.24.10/gdk/gdkwindow.c +=================================================================== +--- gtk+2.0-2.24.10.orig/gdk/gdkwindow.c 2011-11-08 21:20:20.000000000 +0400 ++++ gtk+2.0-2.24.10/gdk/gdkwindow.c 2015-06-03 11:04:06.943458223 +0300 +@@ -2545,13 +2545,18 @@ + { + filter = (GdkEventFilter *)tmp_list->data; + if ((filter->function == function) && (filter->data == data)) +- return; ++ { ++ filter->ref_count++; ++ return; ++ } + tmp_list = tmp_list->next; + } + + filter = g_new (GdkEventFilter, 1); + filter->function = function; + filter->data = data; ++ filter->ref_count = 1; ++ filter->flags = 0; + + if (private) + private->filters = g_list_append (private->filters, filter); +@@ -2593,16 +2598,21 @@ + tmp_list = tmp_list->next; + + if ((filter->function == function) && (filter->data == data)) +- { +- if (private) +- private->filters = g_list_remove_link (private->filters, node); +- else +- _gdk_default_filters = g_list_remove_link (_gdk_default_filters, node); +- g_list_free_1 (node); +- g_free (filter); ++ { ++ filter->flags |= GDK_EVENT_FILTER_REMOVED; ++ filter->ref_count--; ++ if (filter->ref_count != 0) ++ return; ++ ++ if (private) ++ private->filters = g_list_remove_link (private->filters, node); ++ else ++ _gdk_default_filters = g_list_remove_link (_gdk_default_filters, node); ++ g_list_free_1 (node); ++ g_free (filter); + +- return; +- } ++ return; ++ } + } + } + +Index: gtk+2.0-2.24.10/gdk/quartz/gdkevents-quartz.c +=================================================================== +--- gtk+2.0-2.24.10.orig/gdk/quartz/gdkevents-quartz.c 2012-02-06 17:48:55.000000000 +0400 ++++ gtk+2.0-2.24.10/gdk/quartz/gdkevents-quartz.c 2015-06-03 11:03:31.579457499 +0300 +@@ -200,21 +200,42 @@ + static gint + gdk_event_apply_filters (NSEvent *nsevent, + GdkEvent *event, +- GList *filters) ++ GList **filters) + { + GList *tmp_list; + GdkFilterReturn result; + +- tmp_list = filters; ++ tmp_list = *filters; + + while (tmp_list) + { + GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data; +- +- tmp_list = tmp_list->next; ++ GList *node; ++ ++ if ((filter->flags & GDK_EVENT_FILTER_REMOVED) != 0) ++ { ++ tmp_list = tmp_list->next; ++ continue; ++ } ++ ++ filter->ref_count++; + result = filter->function (nsevent, event, filter->data); +- if (result != GDK_FILTER_CONTINUE) +- return result; ++ ++ /* get the next node after running the function since the ++ function may add or remove a next node */ ++ node = tmp_list; ++ tmp_list = tmp_list->next; ++ ++ filter->ref_count--; ++ if (filter->ref_count == 0) ++ { ++ *filters = g_list_remove_link (*filters, node); ++ g_list_free_1 (node); ++ g_free (filter); ++ } ++ ++ if (result != GDK_FILTER_CONTINUE) ++ return result; + } + + return GDK_FILTER_CONTINUE; +@@ -1199,7 +1220,7 @@ + /* Apply global filters */ + GdkFilterReturn result; + +- result = gdk_event_apply_filters (nsevent, event, _gdk_default_filters); ++ result = gdk_event_apply_filters (nsevent, event, &_gdk_default_filters); + if (result != GDK_FILTER_CONTINUE) + { + return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; +@@ -1264,19 +1285,19 @@ + GdkFilterReturn result; + + if (filter_private->filters) +- { +- g_object_ref (window); ++ { ++ g_object_ref (window); + +- result = gdk_event_apply_filters (nsevent, event, filter_private->filters); ++ result = gdk_event_apply_filters (nsevent, event, &filter_private->filters); + +- g_object_unref (window); ++ g_object_unref (window); + +- if (result != GDK_FILTER_CONTINUE) +- { +- return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; +- goto done; +- } +- } ++ if (result != GDK_FILTER_CONTINUE) ++ { ++ return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; ++ goto done; ++ } ++ } + } + + /* If the app is not active leave the event to AppKit so the window gets +Index: gtk+2.0-2.24.10/gdk/win32/gdkevents-win32.c +=================================================================== +--- gtk+2.0-2.24.10.orig/gdk/win32/gdkevents-win32.c 2011-11-08 21:20:20.000000000 +0400 ++++ gtk+2.0-2.24.10/gdk/win32/gdkevents-win32.c 2015-06-03 11:03:31.583457499 +0300 +@@ -1069,7 +1069,7 @@ + static GdkFilterReturn + apply_event_filters (GdkWindow *window, + MSG *msg, +- GList *filters) ++ GList **filters) + { + GdkFilterReturn result = GDK_FILTER_CONTINUE; + GdkEvent *event; +@@ -1087,15 +1087,36 @@ + */ + node = _gdk_event_queue_append (_gdk_display, event); + +- tmp_list = filters; ++ tmp_list = *filters; + while (tmp_list) + { + GdkEventFilter *filter = (GdkEventFilter *) tmp_list->data; +- +- tmp_list = tmp_list->next; ++ GList *node; ++ ++ if ((filter->flags & GDK_EVENT_FILTER_REMOVED) != 0) ++ { ++ tmp_list = tmp_list->next; ++ continue; ++ } ++ ++ filter->ref_count++; + result = filter->function (msg, event, filter->data); +- if (result != GDK_FILTER_CONTINUE) +- break; ++ ++ /* get the next node after running the function since the ++ function may add or remove a next node */ ++ node = tmp_list; ++ tmp_list = tmp_list->next; ++ ++ filter->ref_count--; ++ if (filter->ref_count == 0) ++ { ++ *filters = g_list_remove_link (*filters, node); ++ g_list_free_1 (node); ++ g_free (filter); ++ } ++ ++ if (result != GDK_FILTER_CONTINUE) ++ break; + } + + if (result == GDK_FILTER_CONTINUE || result == GDK_FILTER_REMOVE) +@@ -2075,7 +2096,7 @@ + { + /* Apply global filters */ + +- GdkFilterReturn result = apply_event_filters (NULL, msg, _gdk_default_filters); ++ GdkFilterReturn result = apply_event_filters (NULL, msg, &_gdk_default_filters); + + /* If result is GDK_FILTER_CONTINUE, we continue as if nothing + * happened. If it is GDK_FILTER_REMOVE or GDK_FILTER_TRANSLATE, +@@ -2121,7 +2142,7 @@ + { + /* Apply per-window filters */ + +- GdkFilterReturn result = apply_event_filters (window, msg, ((GdkWindowObject *) window)->filters); ++ GdkFilterReturn result = apply_event_filters (window, msg, &((GdkWindowObject *) window)->filters); + + if (result == GDK_FILTER_REMOVE || result == GDK_FILTER_TRANSLATE) + { +Index: gtk+2.0-2.24.10/gdk/x11/gdkevents-x11.c +=================================================================== +--- gtk+2.0-2.24.10.orig/gdk/x11/gdkevents-x11.c 2011-08-16 06:30:52.000000000 +0400 ++++ gtk+2.0-2.24.10/gdk/x11/gdkevents-x11.c 2015-06-03 11:04:06.827458221 +0300 +@@ -96,7 +96,7 @@ + + static gint gdk_event_apply_filters (XEvent *xevent, + GdkEvent *event, +- GList *filters); ++ GList **filters); + static gboolean gdk_event_translate (GdkDisplay *display, + GdkEvent *event, + XEvent *xevent, +@@ -341,21 +341,42 @@ + static gint + gdk_event_apply_filters (XEvent *xevent, + GdkEvent *event, +- GList *filters) ++ GList **filters) + { + GList *tmp_list; + GdkFilterReturn result; + +- tmp_list = filters; ++ tmp_list = *filters; + + while (tmp_list) + { + GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data; ++ GList *node; + +- tmp_list = tmp_list->next; ++ if ((filter->flags & GDK_EVENT_FILTER_REMOVED) != 0) ++ { ++ tmp_list = tmp_list->next; ++ continue; ++ } ++ ++ filter->ref_count++; + result = filter->function (xevent, event, filter->data); +- if (result != GDK_FILTER_CONTINUE) +- return result; ++ ++ /* get the next node after running the function since the ++ function may add or remove a next node */ ++ node = tmp_list; ++ tmp_list = tmp_list->next; ++ ++ filter->ref_count--; ++ if (filter->ref_count == 0) ++ { ++ *filters = g_list_remove_link (*filters, node); ++ g_list_free_1 (node); ++ g_free (filter); ++ } ++ ++ if (result != GDK_FILTER_CONTINUE) ++ return result; + } + + return GDK_FILTER_CONTINUE; +@@ -925,7 +946,7 @@ + /* Apply global filters */ + GdkFilterReturn result; + result = gdk_event_apply_filters (xevent, event, +- _gdk_default_filters); ++ &_gdk_default_filters); + + if (result != GDK_FILTER_CONTINUE) + { +@@ -1031,7 +1052,7 @@ + g_object_ref (filter_window); + + result = gdk_event_apply_filters (xevent, event, +- filter_private->filters); ++ &filter_private->filters); + + g_object_unref (filter_window); + diff -Nru gtk+2.0-2.24.10/debian/patches/gdk-Fix-GdkWindowFilter-internal-refcounting.patch gtk+2.0-2.24.10/debian/patches/gdk-Fix-GdkWindowFilter-internal-refcounting.patch --- gtk+2.0-2.24.10/debian/patches/gdk-Fix-GdkWindowFilter-internal-refcounting.patch 1970-01-01 03:00:00.000000000 +0300 +++ gtk+2.0-2.24.10/debian/patches/gdk-Fix-GdkWindowFilter-internal-refcounting.patch 2015-06-03 11:04:15.000000000 +0300 @@ -0,0 +1,236 @@ +From 5efefdb6550b3f00d5ca159c2ff74326bfd0e94b Mon Sep 17 00:00:00 2001 +From: Christophe Fergeau +Date: Tue, 3 Mar 2015 15:37:41 +0100 +Subject: gdk: Fix GdkWindowFilter internal refcounting + +Running gnome-shell under valgrind, I saw the attached invalid write. +Basically we can destroy a window during event processing, and the old +window_remove_filters simply called g_free() on the filter, ignoring +the refcount. Then later in event processing we call filter->refcount--, +which is writing to free()d memory. + +Fix this by centralizing list mutation and refcount handling inside +a new shared _gdk_window_filter_unref() function, and using that +everywhere. + +==13876== Invalid write of size 4 +==13876== at 0x446B181: gdk_event_apply_filters (gdkeventsource.c:86) +==13876== by 0x446B411: _gdk_events_queue (gdkeventsource.c:188) +==13876== by 0x44437EF: gdk_display_get_event (gdkdisplay.c:410) +==13876== by 0x446B009: gdk_event_source_dispatch (gdkeventsource.c:317) +==13876== by 0x4AB7159: g_main_context_dispatch (gmain.c:2436) +==13876== by 0x4AB7957: g_main_context_iterate.clone.5 (gmain.c:3087) +==13876== by 0x4AB806A: g_main_loop_run (gmain.c:3295) +==13876== by 0x8084D6B: main (main.c:722) +==13876== Address 0x1658bcac is 12 bytes inside a block of size 16 free'd +==13876== at 0x4005EAD: free (vg_replace_malloc.c:366) +==13876== by 0x4ABE515: g_free (gmem.c:263) +==13876== by 0x444BCC9: window_remove_filters (gdkwindow.c:1873) +==13876== by 0x4454BA3: _gdk_window_destroy_hierarchy (gdkwindow.c:2043) +==13876== by 0x447BF6E: gdk_window_destroy_notify (gdkwindow-x11.c:1115) +==13876== by 0x43588E2: _gtk_socket_windowing_filter_func (gtksocket-x11.c:518) +==13876== by 0x446B170: gdk_event_apply_filters (gdkeventsource.c:79) +==13876== by 0x446B411: _gdk_events_queue (gdkeventsource.c:188) +==13876== by 0x44437EF: gdk_display_get_event (gdkdisplay.c:410) +==13876== by 0x446B009: gdk_event_source_dispatch (gdkeventsource.c:317) +==13876== by 0x4AB7159: g_main_context_dispatch (gmain.c:2436) +==13876== by 0x4AB7957: g_main_context_iterate.clone.5 (gmain.c:3087) + +https://bugzilla.gnome.org/show_bug.cgi?id=637464 + +Backport of 806c04411d306680353cf90cffee98ce73e122f2 to +the gtk-2-24 branch. 806c0441 was authored by Colin Walters + + +Without this patch, the spotify linux client was crashing during +playback of some songs when using gtk+ 2.24.26 + +https://bugzilla.gnome.org/show_bug.cgi?id=745536 + +Index: gtk+2.0-2.24.10/gdk/gdkinternals.h +=================================================================== +--- gtk+2.0-2.24.10.orig/gdk/gdkinternals.h 2015-06-03 11:04:06.731458219 +0300 ++++ gtk+2.0-2.24.10/gdk/gdkinternals.h 2015-06-03 11:04:13.623458360 +0300 +@@ -299,6 +299,9 @@ + void _gdk_events_queue (GdkDisplay *display); + GdkEvent* _gdk_event_unqueue (GdkDisplay *display); + ++void _gdk_event_filter_unref (GdkWindow *window, ++ GdkEventFilter *filter); ++ + GList* _gdk_event_queue_find_first (GdkDisplay *display); + void _gdk_event_queue_remove_link (GdkDisplay *display, + GList *node); +Index: gtk+2.0-2.24.10/gdk/gdkwindow.c +=================================================================== +--- gtk+2.0-2.24.10.orig/gdk/gdkwindow.c 2015-06-03 11:04:06.943458223 +0300 ++++ gtk+2.0-2.24.10/gdk/gdkwindow.c 2015-06-03 11:04:13.627458360 +0300 +@@ -1931,23 +1931,62 @@ + return TRUE; + } + +-static void +-window_remove_filters (GdkWindow *window) ++/** ++ * _gdk_event_filter_unref: ++ * @window: (allow-none): A #GdkWindow, or %NULL to be the global window ++ * @filter: A window filter ++ * ++ * Release a reference to @filter. Note this function may ++ * mutate the list storage, so you need to handle this ++ * if iterating over a list of filters. ++ */ ++void ++_gdk_event_filter_unref (GdkWindow *window, ++ GdkEventFilter *filter) + { +- GdkWindowObject *obj = (GdkWindowObject*) window; ++ GList **filters; ++ GList *tmp_list; ++ ++ if (window == NULL) ++ filters = &_gdk_default_filters; ++ else ++ { ++ GdkWindowObject *private; ++ private = (GdkWindowObject *) window; ++ filters = &private->filters; ++ } + +- if (obj->filters) ++ for (tmp_list = *filters; tmp_list; tmp_list = tmp_list->next) + { +- GList *tmp_list; ++ GdkEventFilter *iter_filter = tmp_list->data; ++ GList *node; + +- for (tmp_list = obj->filters; tmp_list; tmp_list = tmp_list->next) +- g_free (tmp_list->data); ++ if (iter_filter != filter) ++ continue; + +- g_list_free (obj->filters); +- obj->filters = NULL; ++ g_assert (iter_filter->ref_count > 0); ++ ++ filter->ref_count--; ++ if (filter->ref_count != 0) ++ continue; ++ ++ node = tmp_list; ++ tmp_list = tmp_list->next; ++ ++ *filters = g_list_remove_link (*filters, node); ++ g_free (filter); ++ g_list_free_1 (node); + } + } + ++static void ++window_remove_filters (GdkWindow *window) ++{ ++ GdkWindowObject *obj = (GdkWindowObject*) window; ++ while (obj->filters) ++ _gdk_event_filter_unref (window, obj->filters->data); ++} ++ + /** + * _gdk_window_destroy_hierarchy: + * @window: a #GdkWindow +@@ -2600,16 +2639,7 @@ + if ((filter->function == function) && (filter->data == data)) + { + filter->flags |= GDK_EVENT_FILTER_REMOVED; +- filter->ref_count--; +- if (filter->ref_count != 0) +- return; +- +- if (private) +- private->filters = g_list_remove_link (private->filters, node); +- else +- _gdk_default_filters = g_list_remove_link (_gdk_default_filters, node); +- g_list_free_1 (node); +- g_free (filter); ++ _gdk_event_filter_unref (window, filter); + + return; + } +Index: gtk+2.0-2.24.10/gdk/x11/gdkevents-x11.c +=================================================================== +--- gtk+2.0-2.24.10.orig/gdk/x11/gdkevents-x11.c 2015-06-03 11:04:06.827458221 +0300 ++++ gtk+2.0-2.24.10/gdk/x11/gdkevents-x11.c 2015-06-03 11:04:13.627458360 +0300 +@@ -96,7 +96,7 @@ + + static gint gdk_event_apply_filters (XEvent *xevent, + GdkEvent *event, +- GList **filters); ++ GdkWindow *window); + static gboolean gdk_event_translate (GdkDisplay *display, + GdkEvent *event, + XEvent *xevent, +@@ -341,12 +341,20 @@ + static gint + gdk_event_apply_filters (XEvent *xevent, + GdkEvent *event, +- GList **filters) ++ GdkWindow *window) + { + GList *tmp_list; + GdkFilterReturn result; + +- tmp_list = *filters; ++ if (window == NULL) ++ tmp_list = _gdk_default_filters; ++ else ++ { ++ GdkWindowObject *window_private; ++ window_private = (GdkWindowObject *) window; ++ tmp_list = window_private->filters; ++ } ++ + + while (tmp_list) + { +@@ -362,18 +370,12 @@ + filter->ref_count++; + result = filter->function (xevent, event, filter->data); + +- /* get the next node after running the function since the +- function may add or remove a next node */ +- node = tmp_list; +- tmp_list = tmp_list->next; ++ /* Protect against unreffing the filter mutating the list */ ++ node = tmp_list->next; + +- filter->ref_count--; +- if (filter->ref_count == 0) +- { +- *filters = g_list_remove_link (*filters, node); +- g_list_free_1 (node); +- g_free (filter); +- } ++ _gdk_event_filter_unref (window, filter); ++ ++ tmp_list = node; + + if (result != GDK_FILTER_CONTINUE) + return result; +@@ -945,8 +947,7 @@ + { + /* Apply global filters */ + GdkFilterReturn result; +- result = gdk_event_apply_filters (xevent, event, +- &_gdk_default_filters); ++ result = gdk_event_apply_filters (xevent, event, NULL); + + if (result != GDK_FILTER_CONTINUE) + { +@@ -1052,7 +1053,7 @@ + g_object_ref (filter_window); + + result = gdk_event_apply_filters (xevent, event, +- &filter_private->filters); ++ filter_window); + + g_object_unref (filter_window); + diff -Nru gtk+2.0-2.24.10/debian/patches/gdkwindow-Fix-event-unref-iteration.patch gtk+2.0-2.24.10/debian/patches/gdkwindow-Fix-event-unref-iteration.patch --- gtk+2.0-2.24.10/debian/patches/gdkwindow-Fix-event-unref-iteration.patch 1970-01-01 03:00:00.000000000 +0300 +++ gtk+2.0-2.24.10/debian/patches/gdkwindow-Fix-event-unref-iteration.patch 2015-06-03 11:04:32.000000000 +0300 @@ -0,0 +1,40 @@ +From 22eb70adab72a5c14f063ea15f8195087ff1dcd8 Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Fri, 17 Dec 2010 15:36:51 -0500 +Subject: gdkwindow: Fix event unref iteration + +We were double looping previously which caused a NULL deref. + +(cherry picked from commit d08ff485f28f23427bff1b3aac64ab3f77a8664d) + +Index: gtk+2.0-2.24.10/gdk/gdkwindow.c +=================================================================== +--- gtk+2.0-2.24.10.orig/gdk/gdkwindow.c 2015-06-03 11:04:13.627458360 +0300 ++++ gtk+2.0-2.24.10/gdk/gdkwindow.c 2015-06-03 11:04:29.123458677 +0300 +@@ -1956,11 +1956,15 @@ + filters = &private->filters; + } + +- for (tmp_list = *filters; tmp_list; tmp_list = tmp_list->next) ++ tmp_list = *filters; ++ while (tmp_list) + { + GdkEventFilter *iter_filter = tmp_list->data; + GList *node; + ++ node = tmp_list; ++ tmp_list = tmp_list->next; ++ + if (iter_filter != filter) + continue; + +@@ -1970,9 +1974,6 @@ + if (filter->ref_count != 0) + continue; + +- node = tmp_list; +- tmp_list = tmp_list->next; +- + *filters = g_list_remove_link (*filters, node); + g_free (filter); + g_list_free_1 (node); diff -Nru gtk+2.0-2.24.10/debian/patches/series gtk+2.0-2.24.10/debian/patches/series --- gtk+2.0-2.24.10/debian/patches/series 2014-02-06 19:22:14.000000000 +0400 +++ gtk+2.0-2.24.10/debian/patches/series 2015-06-03 11:04:26.000000000 +0300 @@ -26,3 +26,6 @@ 099_printer_filename_fix.patch 100_overlay_scrollbar_loading.patch backport_search_printer_location.patch +fix_gdk_event_apply_filters.patch +gdk-Fix-GdkWindowFilter-internal-refcounting.patch +gdkwindow-Fix-event-unref-iteration.patch