GNOME Bugzilla – Bug 729651
Crash in GtkFileChooserButton with appears-as-list
Last modified: 2017-08-27 20:11:56 UTC
Meld crashes on directory selection for directory comparison on Kubuntu. Steps to reproduce: - Start meld. - On the main screen select directory comparison mode. - Select one of the directories to compare by choosing Other in one of the combo-boxes below. - Meld crashes. This problem have been reported multiple times: Meld bug: https://bugzilla.gnome.org/show_bug.cgi?id=712582 KDE bug: https://bugs.kde.org/show_bug.cgi?id=326424 There are several backtraces and some analysis in these bugs. The problem appears at least in Kubuntu 13.10 and 14.04 x86_64.
Note: the same crash also happens with gtk-demo, selecting "pickers" and trying to change the "folder" box to any value. The crash happens with any widget theme, provided that GtkComboBox::appears-as-list = 1
+ Trace 233571
I successfully reproduce this bug with the following test application, under Fedora 19 with KDE 4.11.5, GTK3 version 3.8.8. However it crashes whenever I choose an item from the combo box, no matter what option I choose. #include <gtk/gtk.h> static void activate_main_window(GtkApplication *app, gpointer user_data) { GtkWidget *main_window = gtk_application_window_new(app); GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); GtkWidget *file_chooser = gtk_file_chooser_button_new("test", GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); gtk_container_add(GTK_CONTAINER(box), file_chooser); gtk_container_add(GTK_CONTAINER(main_window), box); gtk_widget_show_all(main_window); } int main(int argc, char **argv) { GtkApplication *app = gtk_application_new(NULL, G_APPLICATION_FLAGS_NONE); g_signal_connect(app, "activate", G_CALLBACK(activate_main_window), NULL); g_application_run(G_APPLICATION(app), argc, argv); g_object_unref(app); return 0; }
Backtrace from gdb
+ Trace 233629
For crying out loud, this bug is almost a year old and it's still 100% reproducible on Kubuntu 14.10. Don't you care your users have constant crashes?
Please don't conflate the unnecessarily combative "don't care [about] your users" with the reality, which is 'have limited resources to debug the deprecated side of a baffling dual-mode widget'. GtkComboBox would be confusing enough on its own, but the GTK+ 3 implementation where nearly every code path is conditional on the current mode does not exactly lend itself to swift diagnosis.
fwiw, another for the pile (a.out:455): Gtk-CRITICAL **: gtk_tree_model_filter_get_value: assertion 'GTK_TREE_MODEL_FILTER (model)->priv->stamp == iter->stamp' failed (a.out:455): GLib-GObject-WARNING **: /build/glib2.0-y6934K/glib2.0-2.42.1/./gobject/gtype.c:4221: type id '0' is invalid (a.out:455): GLib-GObject-WARNING **: can't peek value table for type '<invalid>' which is not currently referenced Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7808477 in gtk_tree_model_get_valist ( tree_model=tree_model@entry=0x967160, iter=iter@entry=0x7fffffffdb00, var_args=var_args@entry=0x7fffffffd9b0) at /tmp/buildd/gtk+3.0-3.14.5/./gtk/gtktreemodel.c:1797 1797 /tmp/buildd/gtk+3.0-3.14.5/./gtk/gtktreemodel.c: No such file or directory. (gdb) bt
+ Trace 237847
[yes, I'm stuck on an ancient machine, but I doubt much has changed in the list-mode code since then] $ valgrind ./a.out ==1882== Memcheck, a memory error detector ==1882== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. ==1882== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info ==1882== Command: ./a.out ==1882== (a.out:1882): Gtk-CRITICAL **: gtk_tree_model_filter_get_value: assertion 'GTK_TREE_MODEL_FILTER (model)->priv->stamp == iter->stamp' failed (a.out:1882): GLib-GObject-WARNING **: /build/glib2.0-y6934K/glib2.0-2.42.1/./gobject/gtype.c:4221: type id '0' is invalid (a.out:1882): GLib-GObject-WARNING **: can't peek value table for type '<invalid>' which is not currently referenced ==1882== Invalid read of size 8 ==1882== at 0x5119477: gtk_tree_model_get_valist (gtktreemodel.c:1797) ==1882== by 0x5119798: gtk_tree_model_get (gtktreemodel.c:1759) ==1882== by 0x4FB9AFD: combo_box_row_separator_func (gtkfilechooserbutton.c:2331) ==1882== by 0x4F69744: tree_column_row_is_sensitive (gtkcombobox.c:2197) ==1882== by 0x4F6F081: gtk_combo_box_list_button_released (gtkcombobox.c:3771) ==1882== by 0x502234C: _gtk_marshal_BOOLEAN__BOXED (gtkmarshalers.c:85) ==1882== by 0x6AF5244: g_closure_invoke (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1) ==1882== by 0x6B06F6B: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1) ==1882== by 0x6B0F284: g_signal_emit_valist (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1) ==1882== by 0x6B0F9DE: g_signal_emit (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1) ==1882== by 0x5152E33: gtk_widget_event_internal (gtkwidget.c:7773) ==1882== by 0x501FD5D: propagate_event_up (gtkmain.c:2424) ==1882== by 0x501FD5D: propagate_event (gtkmain.c:2526) ==1882== Address 0x30 is not stack'd, malloc'd or (recently) free'd ==1882== ==1882== ==1882== Process terminating with default action of signal 11 (SIGSEGV) ==1882== Access not within mapped region at address 0x30 ==1882== at 0x5119477: gtk_tree_model_get_valist (gtktreemodel.c:1797) ==1882== by 0x5119798: gtk_tree_model_get (gtktreemodel.c:1759) ==1882== by 0x4FB9AFD: combo_box_row_separator_func (gtkfilechooserbutton.c:2331) ==1882== by 0x4F69744: tree_column_row_is_sensitive (gtkcombobox.c:2197) ==1882== by 0x4F6F081: gtk_combo_box_list_button_released (gtkcombobox.c:3771) ==1882== by 0x502234C: _gtk_marshal_BOOLEAN__BOXED (gtkmarshalers.c:85) ==1882== by 0x6AF5244: g_closure_invoke (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1) ==1882== by 0x6B06F6B: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1) ==1882== by 0x6B0F284: g_signal_emit_valist (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1) ==1882== by 0x6B0F9DE: g_signal_emit (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1) ==1882== by 0x5152E33: gtk_widget_event_internal (gtkwidget.c:7773) ==1882== by 0x501FD5D: propagate_event_up (gtkmain.c:2424) ==1882== by 0x501FD5D: propagate_event (gtkmain.c:2526) ==1882== If you believe this happened as a result of a stack ==1882== overflow in your program's main thread (unlikely but ==1882== possible), you can try to increase the size of the ==1882== main thread stack using the --main-stacksize= flag. ==1882== The main thread stack size used in this run was 8388608. ==1882== ==1882== HEAP SUMMARY: ==1882== in use at exit: 3,235,460 bytes in 38,815 blocks ==1882== total heap usage: 312,626 allocs, 273,811 frees, 18,002,253 bytes allocated ==1882== ==1882== LEAK SUMMARY: ==1882== definitely lost: 21,814 bytes in 12 blocks ==1882== indirectly lost: 28,093 bytes in 1,118 blocks ==1882== possibly lost: 149,776 bytes in 2,130 blocks ==1882== still reachable: 2,789,225 bytes in 34,198 blocks ==1882== suppressed: 0 bytes in 0 blocks ==1882== Rerun with --leak-check=full to see details of leaked memory ==1882== ==1882== For counts of detected and suppressed errors, rerun with: -v ==1882== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) Killed
FileChooserButton does shenanigans with its filtered model (TreeModelFilter) when ComboBox:popup-shown changes. I wonder if that makes the iterator that we get in gtk_combo_box_list_button_released() invalid - as we get it, then call popdown(), THEN try to select the iter. If so, UB means all bets are off beyond that point. The testcase in bug 703511, which doesn't use FileChooserButton, /does/ also use a filtered model, though afaict all rows are always visible in the simple code path that still crashes, and nothing should make its filtered model be rebuilt.
Created attachment 358441 [details] [review] ComboBox: Use iter before popdown() may invalidate Bad actors, such as our very own FileChooserButton, may connect to the :popped-up property and alter the model as the menu becomes in/visible. We were first getting an iter into the model while popped-up, then doing popdown(), then using the iter, which may have just become invalidated by the errant :popped-up handler. If so, crash city is the destination. This is clearly bonkers, but until such patterns are removed, we have to work around them. So, set_active() from the popped-up path while it is known to be valid, by moving the call to set_active() before popdown(). While here, change set_active_iter(iter) to set_active_internal(path) to avoid pointlessly going through the iter to get the path we already have -- This seems to fix it for me - confirmation from other affected users appreciated
(btw, this patch has no discernible effect on bug 703511)
Comment on attachment 358441 [details] [review] ComboBox: Use iter before popdown() may invalidate pushed (with tweaks to commentary) to gtk-2-24 and gtk-3-22
*** Bug 712582 has been marked as a duplicate of this bug. ***
D'oh. Don't skip history class. I just realised this fix conflicts with the following commit (incompletely). So it may need to be reverted if that matters. If so, consider this advance warning/apology for users on either side of this. Anyway, re-breaking this might be a blessing in disguise in reality: Firstly, list mode has a host of other ugly bugs making it impractical for many other reasons, and it’s deprecated in GTK+ 3 and removed in 4. Secondly, GtkFileChooserButton isn’t, so the real fix is to make it stop pulling the model out from underneath GtkComboBox while popping up/down. That is the real problem, albeit not one that lends itself to such simple 'fixes' as mine. commit 097e3b0b1fd7d34887df3f03e2915a408a9c8f5b Author: Matthias Clasen <mclasen@redhat.com> Date: Wed Mar 15 19:00:59 2006 +0000 Popdown the list before changing the active iter, otherwise people will be 2006-03-15 Matthias Clasen <mclasen@redhat.com> * gtk/gtkcombobox.c (gtk_combo_box_list_button_released) (gtk_combo_box_list_key_press): Popdown the list before changing the active iter, otherwise people will be surprised by the grabs that are still in place when their ::changed handler runs.
If the fix is reverted, please reopen the bug.
Of course. Anyway, I hope not to need to, and to push a patch that satisfies both sets of expectations simultaneously: https://bugzilla.gnome.org/show_bug.cgi?id=786835