GNOME Bugzilla – Bug 732051
Crash can result if a child widget is destroyed while its tab is being dragged
Last modified: 2015-01-30 17:40:39 UTC
If a child widget is destroyed while its tab is being dragged, this causes problems for the application when it receives a signal at the end of the drag ("create-window", "page-added", "page-reordered" etc) referring to a child widget that no longer exists. It typically results in a crash. This can be demonstrated in gnome-terminal and roxterm as described at <https://sourceforge.net/p/roxterm/bugs/105/>. I don't think there's an easy way for an application to keep track of whether a tab is being dragged and thus avoid this problem, so please could GtkNotebook automatically cancel any drag if the child widget is destroyed.
*** Bug 732034 has been marked as a duplicate of this bug. ***
Bumping severity to critical, according to bugzilla's help page. I could not think of any way to work around the issue in gnome-terminal. There seems to be no way to programatically cancel a pending DND event, and there's no way to query if a DND is in progress (to keep the terminal tab alive for the DND's duration), so the crash is inevitable.
I don't think it is ok for you to destroy the widget after you gave it to one of the notebook tab-adding functions. The notebook takes ownership of it.
I disagree, a GtkContainer should be able to handle a child widget being destroyed without it being removed first. The docs for gtk_container_remove() actually recommend destroying without explicitly removing. And anyway, do we know that it's safe to call gtk_container_remove() or gtk_notebook_remove_page() on a page that's being dragged without triggering this same bug?
I have to concur with comment 4. How else is one supposed to handle this (other than disabling tab DND) ?
The title of the bug is a bit misleading. The widget is of course first removed from the notebook with gtk_container_remove(), and then destroyed. Just as the notebook takes ownership on gtk_container_add(), it needs to release ownership on gtk_container_remove() (aborting the DND if necessary) so from this point on the caller is safe to destroy the object. Or it should hold an extra ref while DNDing (but that'd lead to a more complex solution).
Created attachment 295447 [details] [review] GtkNotebook: Don't crash if the child disappeared during DND
The fix for this looks simple to me and GtkNotebook is already careful enough to handle this in a few other places. Reopening.
Thanks Debarshi! Tested with gtk+-3.12.2 I confirm that the originally reported crash is gone. However, I've just discovered that the story is more complicated. If you try to drop the ceased notebook over a gnome-terminal's terminal area, a "(gnome-terminal-server:12345): Gtk-CRITICAL **: gtk_selection_data_set: assertion 'length <= 0' failed" is printed. If the whole source window disappears, sometimes (about 50% of the cases) I still see a segfault. Open two gnome-terminal windows, in one of them have two tabs. In both of these tabs execute something like "exec sleep 10". Start dragging one of them (it's two possible cases depending on which one will terminate first; but I saw no substantial difference between these two cases). Hold the dragged tab over noone's land (e.g. the desktop). Wait until both tabs and hence the complete window (along with the notebook widget itself) disappears. Then move the mouse over the remaining gnome-terminal window's terminal area. As soon as the mouse enters there, I often get a segfault.
(Without knowing anything about the code) I think it'd be a cleaner design and more robust solution (even against more complicated setups that I still haven't thought of) if gtk_container_remove() first triggered to execute whatever's executed when pressing Escape (except for the UI animation), that is, cancelled the pending DND operation first and then removed it.
Fixed? Does this mean I should open a new bugreport for comment 9's finding?
(In reply to comment #9) > If you try to drop the ceased notebook over a gnome-terminal's terminal area, a > "(gnome-terminal-server:12345): Gtk-CRITICAL **: gtk_selection_data_set: > assertion 'length <= 0' failed" is printed. I can't get it to crash like that. I see these CRITICALS: CRITICAL **: atk_selection_ref_selection: assertion 'ATK_IS_SELECTION (obj)' failed Gtk-CRITICAL **: gtk_accessible_get_widget: assertion 'GTK_IS_ACCESSIBLE (accessible)' failed Do you have a back trace? > If the whole source window disappears, sometimes (about 50% of the cases) I > still see a segfault. Open two gnome-terminal windows, in one of them have two > tabs. In both of these tabs execute something like "exec sleep 10". Start > dragging one of them (it's two possible cases depending on which one will > terminate first; but I saw no substantial difference between these two cases). > Hold the dragged tab over noone's land (e.g. the desktop). Wait until both > tabs and hence the complete window (along with the notebook widget itself) > disappears. Then move the mouse over the remaining gnome-terminal window's > terminal area. As soon as the mouse enters there, I often get a segfault. I can't reproduce this. Back trace could be useful.
(In reply to comment #11) > Fixed? Does this mean I should open a new bugreport for comment 9's finding? I would appreciate testing with whats in master before any more bugs are filed. Bugs are not free...