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 328833 - GtkTreeModelSort cause serious crash, and it's totally unusable.
GtkTreeModelSort cause serious crash, and it's totally unusable.
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Widget: GtkTreeView
2.8.x
Other Linux
: Normal critical
: ---
Assigned To: gtktreeview-bugs
gtktreeview-bugs
Depends on:
Blocks:
 
 
Reported: 2006-01-27 13:37 UTC by Hong Jen Yee
Modified: 2006-02-08 14:26 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Hong Jen Yee 2006-01-27 13:37:46 UTC
I'm developing a new file manager called PCMan File Manager with gtk+ 2.8.10.
http://pcmanfm.sourceforge.net/
This is a high-speed and lightweight file manager compared with most of other file managers.
It can be started ``within one second'', and is ``much more faster'' than GtkFileChooser when 
loading directories with thousands of files. (This is not the point.)
I use all GtkTreeModel related classes to develop my application.
Finally, I found GtkTreeModelSort is unusable.
I use a GtkListStore to store my data, and wrap it with GtkTreeModelSort to do sorting, 
and wrap GtkTreeModelSort with a GtkTreeModelFilter to exclude some hidden files from display.

When I delete ``more than one'' rows at the same time in its child model (GtkListStore), 
the change is ``NOT'' synchronized in its parent model (GtkModelSort).

Hence the toplevel GtkTreeModelFilter ``doesn't know'' there are some rows deleted.
This is unfortunate because the GtkTreeView will ``NOT'' update its display when some rows 
int underlying GtkListStore has been deleted.
Moreover, some GtkTreePaths in toplevel GtkTreeModelFilter will be invalid after their 
counterparts in underlying GtkListStore are deleted.

The wost case is, when I call gtk_tree_model_get_iter in toplevel GtkTreeModelFilter with an 
``INVALID'' path (the real row it refers has been deleted in underlying GtkListStore), the API
still returns TRUE to indicate it gets a ``VALID'' GtkTreeIter for me.
And then, when I call gtk_tree_model_get on this `INVALID` GtkTreeIter, all I get are access violation and segmentation faults.

These serious problems make GtkTreeModelSort and my project totally ``UNUSABLE''.

And when I hack into the source code of GtkTreeModelSort (gtktreemodelsort.c), I got these following comments:

/* WARNING: this code is dangerous, can cause sleepless nights,
 * can cause your dog to die among other bad things
 *
 * we warned you and we're not liable for any head injuries.
 */

/* FIXME: I still have doubts if this works */
static void
gtk_tree_model_sort_row_deleted (GtkTreeModel *s_model,
				 GtkTreePath  *s_path,
				 gpointer      data)

I insist this kind of warnings ``SHOULD'' be put in gtk+ API docs.
I used lots of these things then finally found my project is totally broken 
bacause of unknown bugs of GTK+.  This is very very frustrating.

Neither hacking GtkTreeModelSort to make it work nor rewritting my app with Qt 
are good idea for me.

My project is almost finished, but now totally blocked by GTK+.
Please help me!! This will be a great file manager if these problems can be solved.

Test case: 
I think my project itself is the best test case.
It use GtkTreeView, GtkTreeModel, GtkTreeModelFilter, GtkTreeModelSort, GtkTreePathReference, ...etc. Almost all GtkTreeView related things are used.
Each of these classes seems to work fine, but unfortunately, 
after all these are comboined, I got a broken app.
You can got my source code at SourceForge anonymous CVS.
http://sourceforge.net/cvs/?group_id=156956
BTW, the mothod I used in this project can solve the performance problem 
with GtkFileChooserDialog. So, it's worth hacking. ;-)
Comment 1 Hong Jen Yee 2006-01-27 13:51:28 UTC
The code causing problems in my app is in "src/foldercontent.c"

static void folder_content_delete_file( FolderContent* content,
                                                                        const char* filename );

static gboolean on_fam_event(GIOChannel *channel,
                                                      GIOCondition cond,
                                                      gpointer user_data );

When monitored files on disk are deleted (notified by FAM), I have to 
update the GtkTreeView.
So I install a idle handler with g_idle_add.

Then the handler which will update all folder views is called.
static gboolean call_update_callback( gpointer data );

The update_callback then calls
gboolean update_folder_view_visible_region( FileBrowserData* data )
in src/filebrowser.c

Then, the app crashes because GtkTreeView returns some invalid GtkTreeIters.
(Cause by the preceding problems I described)

In my app, gtk_tree_view_get_visible_range sometimes returns invalid paths, too.
I believe that they are cause by the same problems, the underlying GtkTreeModelSort.
Please help me. After these problems are solved, my app will be a good file manager and 
one of the best demonstration of the power of GtkTreeView/GtkTreeModel.
Comment 2 Matthias Clasen 2006-01-27 22:13:54 UTC
There is no need at all to wrap a list store in a GtkTreeModelSort,
since the liststore is sortable itself.
Comment 3 Hong Jen Yee 2006-01-27 22:41:51 UTC
(In reply to comment #2)
> There is no need at all to wrap a list store in a GtkTreeModelSort,
> since the liststore is sortable itself.
> 
There ``IS'' need if you have ``large set of data''.
Without GtkTreeModelSort, you cannot share the same model between different views, 
if the view items are displayed in different order.
Sort the GtkListStore itself will affect ``ALL'' view diaplaying it.

Using different GtkListStore for different views is a bad idea 
when the list is very large.  This not only greatly increase memory usage, 
but also greatly increase the view creation time 
(Since each view have to create its own list store, and cannot share existing models).
This will induce great performance hit if the large list is created form on-disk files 
or database since the I/O operations are dramatically increased.
Cache the list myself in memory is not a good idea because I have to keep an additional
list to hold all data beside those inside GtkListStores.

If the model is changed in one view, developers will have to synchronize the changes
by themselves between all these duplicated lists.  And this is really a very bad idea.

That's why we need GtkTreeModelSort.
According to GTK+ API doc:
The primary purpose of this model is to provide a way to sort a different model without modifying it.

This is very important.
Using GtkTreeSortable interface has nothing to do with wrapping a GtkListStore with a 
GtkTreeModelSort.  They are totally different thing and serve different needs.
Comment 4 Hong Jen Yee 2006-01-27 23:36:56 UTC
After tracing, I found the problem.
In gtk_tree_model_sort_row_deleted, there is several lines:

  if ( level->ref_count == 0 )
  {
    /* This will prune the level, so I can just emit the signal and
     * not worry about cleaning this level up.
     * Careful, root level is not cleaned up in increment stamp.
     */
    ptk_tree_model_sort_increment_stamp ( tree_model_sort );
    gtk_tree_path_free ( path );
    if ( level == tree_model_sort->root )
    {
      ptk_tree_model_sort_free_level ( tree_model_sort,
                                       tree_model_sort->root );
      tree_model_sort->root = NULL;
    }
    return ;
  }

I found level->ref_count seems to be always 0, and this cause the problem.
After any row is deleted, ``level'' always gets freed.
Hence when aother row in the same level are deleted, there is no ``level'', 
and then ptk_real_tree_model_sort_convert_child_path_to_path cannot 
convert s_path to path since there is no information about current level. 
(level and its internal array has been freed and this shouldn't happen)

So that's why when several rows are deleted at the same time, only the first 
deleted row can correctly emit "row-deleted" signal to its parent.

If you guys can get level->ref_count correctly counted, the bug can be fixed.
Comment 5 Wei-Tsun Sun 2006-01-28 13:36:58 UTC
I have encountered exact the same thing mentioned above. Where the patch supplied by HJ Yee works perfect for me.
Comment 6 Wei-Tsun Sun 2006-01-28 13:41:24 UTC
oops, just realized that it wasn't a patch but just the correction in comment #4.
Comment 7 Kristian Rietveld 2006-02-08 14:26:53 UTC
Compiled pcmanfm (cvs versions HEAD, Jan 28, Jan 25 and Jan 23) against gtk+ HEAD and the problems did not occur.   I assume the problems have been solved by the GtkTreeModelFilter rewrite and GtkTreeModelSort bugfixes in HEAD, if this appears not to be the case later on, please reopen the bug.