GtkTreeModelSorted row-deleted causes SEGV
Steps to reproduce
- Connect a callback to the "row-deleted" signal of a GtkTreeModelSort.
- Remove the last row in the model.
- Loop over all rows in the GtkTreeModelSort inside the callback using gtk_tree_model_get_iter_first() and gtk_tree_model_iter_next(). Call gtk_tree_model_get() on each.
As far as I can tell, there are two errors:
- gtk_tree_model_get_iter_first() should have returned FALSE in the "row-deleted" callback when it is the last row being removed.
- I would have expected gtk_tree_model_get_valist() to handle the invalid iterator gracefully and not caused a SEGV.
The following code reproduces the errors:
#include <gtk/gtk.h>
static void sorted_row_deleted(GtkTreeModel *model, GtkTreePath *path,
gpointer data)
{
GtkTreeIter iter;
// Call should fail - but doesn't
if (gtk_tree_model_get_iter_first(model, &iter)) {
do {
gint val = -1;
// Results in SEGV in call to G_VALUE_COPY() from gtk_tree_model_get_valist()
gtk_tree_model_get(model, &iter,
0, &val,
-1);
} while (gtk_tree_model_iter_next(model, &iter));
}
}
int main(int argc, char *argv[])
{
if (!gtk_parse_args(&argc, &argv) ||
!gtk_init_check(&argc, &argv))
{
return 1;
}
GtkListStore *store = gtk_list_store_new(1, G_TYPE_INT);
GtkTreeModel *sorted =
gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(store));
g_signal_connect_after(G_OBJECT(sorted), "row-deleted",
G_CALLBACK(sorted_row_deleted), NULL);
GtkTreeIter iter;
gtk_list_store_insert_with_values(store, &iter, -1,
0, 123,
-1);
gtk_list_store_remove(store, &iter);
// We do not reach this point
return 0;
}
Version information
libgtk-3-0/bionic-updates,now 3.22.30-1ubuntu4 amd64
Warnings
(sandbox:26506): Gtk-CRITICAL **: 16:44:06.055: gtk_list_store_get_value: assertion 'iter_is_valid (iter, list_store)' failed
(sandbox:26506): GLib-GObject-WARNING **: 16:44:06.055: ../../../../gobject/gtype.c:4265: type id '0' is invalid
(sandbox:26506): GLib-GObject-WARNING **: 16:44:06.055: can't peek value table for type '<invalid>' which is not currently referenced
Segmentation fault (core dumped)
Backtrace
gdb ./sandbox
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./sandbox...done.
(gdb) run
Starting program: /home/kian/repo/lxsw/modules/app/gui/sandbox/src/sandbox
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffedba3700 (LWP 26616)]
[New Thread 0x7fffed3a2700 (LWP 26617)]
(sandbox:26610): Gtk-CRITICAL **: 16:46:12.426: gtk_list_store_get_value: assertion 'iter_is_valid (iter, list_store)' failed
(sandbox:26610): GLib-GObject-WARNING **: 16:46:12.426: ../../../../gobject/gtype.c:4265: type id '0' is invalid
(sandbox:26610): GLib-GObject-WARNING **: 16:46:12.426: can't peek value table for type '<invalid>' which is not currently referenced
Thread 1 "sandbox" received signal SIGSEGV, Segmentation fault.
0x00007ffff780d54d in gtk_tree_model_get_valist (tree_model=tree_model@entry=0x5555557f5940, iter=iter@entry=0x7fffffffd400, var_args=var_args@entry=0x7fffffffd2e0) at ../../../../gtk/gtktreemodel.c:1800
1800 ../../../../gtk/gtktreemodel.c: No such file or directory.
(gdb) bt full
#0 0x00007ffff780d54d in gtk_tree_model_get_valist (tree_model=tree_model@entry=0x5555557f5940, iter=iter@entry=0x7fffffffd400, var_args=var_args@entry=0x7fffffffd2e0) at ../../../../gtk/gtktreemodel.c:1800
_value = 0x7fffffffd230
_flags = 0
_value_type = <optimized out>
_vtable = 0x0
_cvalues =
{{v_int = -10704, v_long = 140737488344624, v_int64 = 140737488344624, v_double = 6.9533558073061565e-310, v_pointer = 0x7fffffffd630}, {v_int = -142523088, v_long = 140737345832240, v_int64 = 140737345832240, v_double = 6.9533487662588523e-310, v_pointer = 0x7ffff7814530 <gtk_tree_model_sort_offset_compare_func>}, {v_int = 1435260448, v_long = 93824995841568, v_int64 = 93824995841568, v_double = 4.6355707166516565e-310, v_pointer = 0x5555558c5620}, {v_int = 1434817568, v_long = 93824995398688, v_int64 = 93824995398688, v_double = 4.6355706947704772e-310, v_pointer = 0x555555859420}, {v_int = 1, v_long = 93823560581121, v_int64 = 93823560581121, v_double = 4.6354998053636868e-310, v_pointer = 0x555500000001}, {v_int = -141506440, v_long = 140737346848888, v_int64 = 140737346848888, v_double = 6.9533488164879374e-310, v_pointer = 0x7ffff790c878}, {v_int = -11104, v_long = 140737488344224, v_int64 = 140737488344224, v_double = 6.9533558072863938e-310, v_pointer = 0x7fffffffd4a0}, {v_int = -196729833, v_long = 140737291625495, v_int64 = 140737291625495, v_double = 6.9533460880898046e-310, v_pointer = 0x7ffff4462417 <g_datalist_get_data+119>}}
_lcopy_format = <optimized out>
_n_values = <optimized out>
value = {g_type = 0, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
error = 0x0
column = 0
__func__ = "gtk_tree_model_get_valist"
#1 0x00007ffff780d83d in gtk_tree_model_get (tree_model=0x5555557f5940, iter=0x7fffffffd400) at ../../../../gtk/gtktreemodel.c:1762
var_args = {{gp_offset = 24, fp_offset = 48, overflow_arg_area = 0x7fffffffd3d0, reg_save_area = 0x7fffffffd300}}
__func__ = "gtk_tree_model_get"
#2 0x0000555555554be2 in sorted_row_deleted (model=0x5555557f5940, path=0x5555558d6db0, data=0x0) at sandbox.c:14
val = -1
iter = {stamp = 713771869, user_data = 0x5555558cb420, user_data2 = 0x5555559dfe00, user_data3 = 0x0}
#3 0x00007ffff728910d in g_closure_invoke () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#4 0x00007ffff729bbf1 in () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#5 0x00007ffff72a4715 in g_signal_emit_valist () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#6 0x00007ffff72a512f in g_signal_emit () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#7 0x00007ffff78174cb in gtk_tree_model_sort_row_deleted (s_model=<optimized out>, s_path=<optimized out>, data=0x5555557f5940) at ../../../../gtk/gtktreemodelsort.c:1060
tree_model_sort = 0x5555557f5940
path = 0x5555558d6db0
elt = 0x5555559dfe00
level = 0x5555558cb420
iter = {stamp = 713771868, user_data = 0x5555558cb420, user_data2 = 0x5555559dfe00, user_data3 = 0x0}
offset = 0
__func__ = "gtk_tree_model_sort_row_deleted"
#8 0x00007ffff728910d in g_closure_invoke () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#9 0x00007ffff729c05e in () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#10 0x00007ffff72a4715 in g_signal_emit_valist () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#11 0x00007ffff72a512f in g_signal_emit () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#12 0x00007ffff76f9309 in gtk_list_store_remove (list_store=0x5555559dccf0, iter=0x7fffffffde00) at ../../../../gtk/gtkliststore.c:1217
priv = 0x5555559dcca0
path = 0x55555587cc50
ptr = 0x7fffe0010e30
next = 0x7fffe0010e60
__func__ = "gtk_list_store_remove"
#13 0x0000555555554d1d in main (argc=1, argv=0x7fffffffdf18) at sandbox.c:47
store = 0x5555559dccf0
sorted = 0x5555557f5940
iter = {stamp = 588212640, user_data = 0x7fffe0010e30, user_data2 = 0x555555554d40 <__libc_csu_init>, user_data3 = 0x555555554a70 <_start>}
(gdb)
Edited by Emmanuele Bassi