After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 711552 - Crash when processing list of GdkWindows
Crash when processing list of GdkWindows
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Backend: X11
2.24.x
Other Linux
: Normal normal
: ---
Assigned To: gtk-bugs
gtk-bugs
Depends on:
Blocks:
 
 
Reported: 2013-11-06 14:35 UTC by Marek Kašík
Modified: 2013-12-18 17:32 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
reproducer (1.19 KB, text/plain)
2013-11-06 14:35 UTC, Marek Kašík
  Details
Handle references in "update_windows" list correctly (3.08 KB, patch)
2013-11-06 14:36 UTC, Marek Kašík
needs-work Details | Review
clear the list in _gdk_window_clear_update_area() (1.59 KB, patch)
2013-11-06 14:36 UTC, Marek Kašík
needs-work Details | Review
Handle references in "update_windows" list correctly (2.63 KB, patch)
2013-12-12 14:23 UTC, Marek Kašík
committed Details | Review
emove GdkWindow with cleared update area from update list (1.54 KB, patch)
2013-12-12 14:25 UTC, Marek Kašík
needs-work Details | Review
Don't add the same window to "update_windows" twice (1.51 KB, patch)
2013-12-17 16:59 UTC, Marek Kašík
accepted-commit_now Details | Review
Don't add the same window to "update_windows" twice (1.10 KB, patch)
2013-12-18 11:28 UTC, Marek Kašík
committed Details | Review

Description Marek Kašík 2013-11-06 14:35:27 UTC
Created attachment 259084 [details]
reproducer

When processing "update_windows" in GdkWindow.c which was not correctly cleared, it can happen that some windows in the list were already destroyed.
E.g. if there are 2 consecutive gtk_main() called in one process then the second one can crash because of this.
Correct reference count handling of added windows prevents such applications
from crash.
Better clearing of the list in _gdk_window_clear_update_area() helps too.

Attached is my reproducer which is based on Selections test from lsb-gtkvts from lsb-test-desktop (compile it with gtk+-2.0).

Marek
Comment 1 Marek Kašík 2013-11-06 14:36:07 UTC
Created attachment 259086 [details] [review]
Handle references in "update_windows" list correctly
Comment 2 Marek Kašík 2013-11-06 14:36:57 UTC
Created attachment 259087 [details] [review]
clear the list in _gdk_window_clear_update_area()
Comment 3 Matthias Clasen 2013-11-09 04:17:18 UTC
Review of attachment 259086 [details] [review]:

::: gdk/gdkwindow.c
@@ +5342,3 @@
 gdk_window_remove_update_window (GdkWindow *window)
 {
+  update_windows = slist_remove_full (update_windows, window, (GDestroyNotify) g_object_unref);

Can just do 

  update_windows = g_slist_remove (update_windows, window);
  g_object_unref (window);

here
Comment 4 Matthias Clasen 2013-11-09 04:24:45 UTC
Review of attachment 259087 [details] [review]:

The patch doesn't apply to git master, it seems.

::: gdk/gdkwindow.c
@@ +6220,3 @@
   if (private->update_area)
     {
+      gdk_window_remove_update_window (window, TRUE);

I would probably just open-code the g_slist_remove_all call here, or add a separate gdk_window_remove_update_window_completely function, instead of a boolean parameter.
Comment 5 Marek Kašík 2013-12-12 14:23:25 UTC
Created attachment 264073 [details] [review]
Handle references in "update_windows" list correctly

(In reply to comment #3)
> Review of attachment 259086 [details] [review]:
> 
> ::: gdk/gdkwindow.c
> @@ +5342,3 @@
>  gdk_window_remove_update_window (GdkWindow *window)
>  {
> +  update_windows = slist_remove_full (update_windows, window, (GDestroyNotify)
> g_object_unref);
> 
> Can just do 
> 
>   update_windows = g_slist_remove (update_windows, window);
>   g_object_unref (window);
> 
> here

I did it this way to be sure to unref the window only if the window was present in the list. I've changed it in the attached patch so that we find the window in the list and unref it then (but it needs 2 iterations over the list instead of 1 now).

I targeted those patches mainly to gtk+-2.24 but we can get them also to master and 3.10 to be sure that there will be no problems in the future (referencing those windows is always good thing to do I guess).
Comment 6 Marek Kašík 2013-12-12 14:25:54 UTC
Created attachment 264074 [details] [review]
emove GdkWindow with cleared update area from update list

(In reply to comment #4)
> Review of attachment 259087 [details] [review]:
> 
> The patch doesn't apply to git master, it seems.
> 
> ::: gdk/gdkwindow.c
> @@ +6220,3 @@
>    if (private->update_area)
>      {
> +      gdk_window_remove_update_window (window, TRUE);
> 
> I would probably just open-code the g_slist_remove_all call here, or add a
> separate gdk_window_remove_update_window_completely function, instead of a
> boolean parameter.

I've added the gdk_window_remove_update_window_completely() function. I had to add there unreferencing of removed window to it (through g_slist_foreach()).
Comment 7 Matthias Clasen 2013-12-13 15:13:46 UTC
Review of attachment 264073 [details] [review]:

::: gdk/gdkwindow.c
@@ +3303,3 @@
+    {
+      update_windows = g_slist_delete_link (update_windows, link);
+      g_object_unref (window);

I think this is fine - the list should be very short, so the double iteration shouldn't matter too much
Comment 8 Matthias Clasen 2013-12-13 15:17:13 UTC
Review of attachment 264074 [details] [review]:

ok
Comment 9 Matthias Clasen 2013-12-13 15:17:30 UTC
Review of attachment 264073 [details] [review]:

.
Comment 10 Matthias Clasen 2013-12-13 15:17:51 UTC
patches look ok to me now, but lets ask alex for a review. this is his area
Comment 11 Alexander Larsson 2013-12-13 15:30:10 UTC
Review of attachment 264073 [details] [review]:

This looks good to me.
Comment 12 Alexander Larsson 2013-12-13 15:30:58 UTC
Review of attachment 264074 [details] [review]:

I don't understand this one though. How can we ever get the same GdkWindow twice in updates_windows?
Comment 13 Marek Kašík 2013-12-16 14:05:20 UTC
(In reply to comment #12)
> Review of attachment 264074 [details] [review]:
> 
> I don't understand this one though. How can we ever get the same GdkWindow
> twice in updates_windows?

Hi Alex,

you can find my findings about this here:

https://bugzilla.redhat.com/show_bug.cgi?id=991365#c3

or here:

https://lsbbugs.linuxfoundation.org/show_bug.cgi?id=3866#c1

Sorry for not mentioning this earlier.

Marek
Comment 14 Marek Kašík 2013-12-16 14:06:47 UTC
I should also mention that my findings are based on gtk+-2.0.
Comment 15 Marek Kašík 2013-12-16 17:17:12 UTC
Comment on attachment 264073 [details] [review]
Handle references in "update_windows" list correctly

Thank you for the review. I've pushed this one to master and 2-24.
Comment 16 Alexander Larsson 2013-12-17 08:49:47 UTC
Review of attachment 264074 [details] [review]:

Rather than having a specialized remove operation in some cases (not very clear when this should be called) I think it makes more sense to have gdk_window_add_update_window() catch the case where the window is already in the list. This function already iterates over update_windows, so that should not make anything less efficient.
Comment 17 Alexander Larsson 2013-12-17 09:06:16 UTC
Also, the code should have a comment pointing out why this can happen.
Comment 18 Marek Kašík 2013-12-17 16:59:52 UTC
Created attachment 264422 [details] [review]
Don't add the same window to "update_windows" twice

(In reply to comment #16)
> Review of attachment 264074 [details] [review]:
> 
> Rather than having a specialized remove operation in some cases (not very clear
> when this should be called) I think it makes more sense to have
> gdk_window_add_update_window() catch the case where the window is already in
> the list. This function already iterates over update_windows, so that should
> not make anything less efficient.

Hi,

I've modified the patch according to your comment. It fixes the problem too.

Btw, could we move the line "GdkWindow *parent = window->parent;" from the cycle? It seems that none of the variables is changed after that.

Regards

Marek
Comment 19 Alexander Larsson 2013-12-18 09:17:23 UTC
Review of attachment 264422 [details] [review]:

Otherwise looks good to me.

::: gdk/gdkwindow.c
@@ +3234,3 @@
+      /*  Check whether "window" is already in "update_windows" list.
+       *  It could be added during execution of gtk_widget_destroy() when
+       *  setting focus widget to NULL and redrawing old focus widget.

Add: "See bug 711552"
Comment 20 Alexander Larsson 2013-12-18 09:18:56 UTC
We could move the parent assignment up, but I doubt it makes any difference, the compiler knows its not modified.
Comment 21 Marek Kašík 2013-12-18 11:28:08 UTC
Created attachment 264470 [details] [review]
Don't add the same window to "update_windows" twice

Hi,

I had to change the patch yet. There is no guarantee that the cycle gets to the same GdkWindow before it adds it again.
The safest thing is to check it before the cycle (but it can happen that the list will be traversed twice :-( ).

Marek
Comment 22 Alexander Larsson 2013-12-18 13:34:49 UTC
Review of attachment 264470 [details] [review]:

Otherwise looks good. I don't think there is a performance issue here anyway, because this is generally a short list of toplevel windows.

::: gdk/gdkwindow.c
@@ +3234,3 @@
+   */
+  tmp = g_slist_find (update_windows, window);
+  if (tmp != NULL && window == tmp->data)

You don't have to check tmp->data, g_slist_find() will return NULL unless it finds the window.
Comment 23 Marek Kašík 2013-12-18 17:32:25 UTC
Comment on attachment 264470 [details] [review]
Don't add the same window to "update_windows" twice

Hi,

thank you for the review.

(In reply to comment #22)
> Review of attachment 264470 [details] [review]:
> 
> Otherwise looks good. I don't think there is a performance issue here anyway,
> because this is generally a short list of toplevel windows.
> 
> ::: gdk/gdkwindow.c
> @@ +3234,3 @@
> +   */
> +  tmp = g_slist_find (update_windows, window);
> +  if (tmp != NULL && window == tmp->data)
> 
> You don't have to check tmp->data, g_slist_find() will return NULL unless it
> finds the window.

I'm not sure what I was thinking about when I was adding it there. Thank you for catching it.

I've pushed the patch to master and gtk-2-24.

Thank you all for your help

Marek