GNOME Bugzilla – Bug 348953
invalid call of free() in glib when expanding or collapsing a tree
Last modified: 2006-07-28 20:43:14 UTC
Steps to reproduce: 1. 2. 3. Stack trace: (gdb) bt
+ Trace 69697
Other information: When I expand the treeview in thunar's sidepane (curent svn) it segfaults due to invalid calls of free(). Benny said this is not a thunar problem as those crashes occur also in versions without explicit usage of g_slice but only the use of gtk. see http://foo-projects.org/pipermail/thunar-dev/2006-July/003150.html I hope g_object was the right place to put this in. I wasn't sure..
A crash like this is basically *ALWAYS* a sign of memory corruptions elsewhere in the applicatin. Please go and tell Benny"to stop telling people to report things like this here :-)
Indeed, plenty of valgrind errors to look at first. In particular, I'd recommend: ==5934== Invalid read of size 4 ==5934== at 0x80AF283: thunar_tree_model_unref_node (thunar-tree-model.c:796) ==5934== by 0x4294919: gtk_tree_model_unref_node (gtktreemodel.c:1363) ==5934== by 0x4297424: gtk_tree_model_filter_real_unref_node (gtktreemodelfil ter.c:2612) ==5934== by 0x42974CC: gtk_tree_model_filter_free_level (gtktreemodelfilter.c :618) ==5934== by 0x429ACA8: gtk_tree_model_filter_row_deleted (gtktreemodelfilter. c:1792) ==5934== by 0x4490E38: g_cclosure_marshal_VOID__BOXED (gmarshal.c:566) ==5934== by 0x4483FFA: g_closure_invoke (gclosure.c:490) ==5934== by 0x4494822: signal_emit_unlocked_R (gsignal.c:2438) ==5934== by 0x4495D46: g_signal_emit_valist (gsignal.c:2197) ==5934== by 0x4495F08: g_signal_emit (gsignal.c:2241) ==5934== by 0x4294634: gtk_tree_model_row_deleted (gtktreemodel.c:1528) ==5934== by 0x80B10E6: thunar_tree_model_item_notify_loading (thunar-tree-mod el.c:1491) ==5934== Address 0x50A6190 is 0 bytes inside a block of size 20 free'd ==5934== at 0x4004FEA: free (vg_replace_malloc.c:233) ==5934== by 0x44E62C0: g_free (gmem.c:187) ==5934== by 0x44F5D25: g_slice_free1 (gslice.c:829) ==5934== by 0x44E96F0: g_nodes_free (gnode.c:62) ==5934== by 0x80B10C4: thunar_tree_model_item_notify_loading (thunar-tree-mod el.c:1487) ==5934== by 0x4490EE8: g_cclosure_marshal_VOID__PARAM (gmarshal.c:531) ==5934== by 0x4483FFA: g_closure_invoke (gclosure.c:490) ==5934== by 0x4494822: signal_emit_unlocked_R (gsignal.c:2438) ==5934== by 0x4495D46: g_signal_emit_valist (gsignal.c:2197) ==5934== by 0x4495F08: g_signal_emit (gsignal.c:2241) ==5934== by 0x44887B0: g_object_dispatch_properties_changed (gobject.c:568) ==5934== by 0x4484DBE: g_object_notify_dispatcher (gobject.c:249) stemming from this bug: --- thunar/,thunar-tree-model.c 2006-07-27 21:40:22.000000000 +0100 +++ thunar/thunar-tree-model.c 2006-07-27 21:39:27.000000000 +0100 @@ -1483,15 +1483,15 @@ path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); if (G_LIKELY (path != NULL)) { - /* drop the dummy from the model */ - g_node_destroy (iter.user_data); - /* notify the view */ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); /* release the path */ gtk_tree_path_free (path); + /* drop the dummy from the model */ + g_node_destroy (iter.user_data); + /* determine the iter to the parent node */ iter.stamp = model->stamp; iter.user_data = node;
Thanks a lot Chris! Your patch worked for me.
Hm, unfortunately now it crashes when I delete a folder :/
The patch does not look right to me. According to the documentation of gtk_tree_model_row_deleted() Emits the "row_deleted" signal on tree_model. This should be called by models after a row has been removed. the node must be unlinked/destroyed first, prior to emitting the "row-deleted" signal.
I just downgraded gtk from 2.10.1 to 2.8.20 and I don't get any crashes with 2.8.* so it must be related to gtk 2.10.
Indeed, running with GTK+ 2.10 makes it crash instantly. It seems to be GtkTreeModelFilter, which is trying to unref a node in the source model after it has been deleted. For example, changing the _row_deleted() code in ThunarTreeModel to GNode *child = node->children; g_node_unlink (child); memset (child, 0xaa, sizeof (*child)); gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); memset (child, 0x00, sizeof (*child)); g_node_destroy (child); you can see it crashing trying to access the no longer valid node filled with 0xaa's: (gdb) r Starting program: /opt/gtk210/bin/Thunar Program received signal SIGSEGV, Segmentation fault.
+ Trace 69718
Thread 1 (LWP 100618)
where thunar-tree-model.c:1493 is the location of the gtk_tree_model_row_deleted() invokation. Maybe I'm missing something, but according to the documentation a row may not be accessed after it has been deleted from the model, and citing gtk_tree_model_unref_node() "Please note that nodes that are deleted are not unreffed" I think that this is a bug in GTK+. BTW: I just checked GtkTreeStore concerning the gtk_tree_model_row_deleted() behaviour and its the same. GtkTreeStore in 2.10 doesn't crash simply because it doesn't implement unref_node(). BTW: The bug should be filed against GTK+ not glib.
Hmm, my reading of the GtkTreeModel is that the refcount is the number of views of the row (which is not the same as the number of owners...). In this case, the GtkTreeModelFilter has an additional view onto the model and so will drop a reference when the row is removed from the filter. However, I have to leave it to the experts for authorative comments.
Just for completeness: Index: thunar/thunar-tree-model.c =================================================================== --- thunar/thunar-tree-model.c (revision 22552) +++ thunar/thunar-tree-model.c (working copy) @@ -1492,12 +1492,12 @@ path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); if (G_LIKELY (path != NULL)) { + /* notify the view */ + gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); + /* drop the dummy from the model */ g_node_destroy (node->children); - /* notify the view */ - gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); - /* determine the iter to the parent node */ iter.stamp = model->stamp; iter.user_data = node; @@ -1573,15 +1573,15 @@ path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); if (G_LIKELY (path != NULL)) { + /* emit a "row-deleted" */ + gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); + /* release the item for the node */ thunar_tree_model_node_traverse_free (node, user_data); /* remove the node from the tree */ g_node_destroy (node); - /* emit a "row-deleted" */ - gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); - /* release the path */ gtk_tree_path_free (path); }