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 551337 - gedit crashes browsing fileselector ssh locations
gedit crashes browsing fileselector ssh locations
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Widget: GtkFileChooser
unspecified
Other Linux
: Normal normal
: ---
Assigned To: gtk-bugs
Federico Mena Quintero
Depends on:
Blocks:
 
 
Reported: 2008-09-08 09:59 UTC by Sebastien Bacher
Modified: 2010-11-25 17:37 UTC
See Also:
GNOME target: ---
GNOME version: 2.23/2.24


Attachments
patch to point out the issue (1.29 KB, patch)
2008-09-08 20:52 UTC, Paolo Borelli
reviewed Details | Review
possible patch (3.62 KB, patch)
2008-09-12 15:47 UTC, Matthias Clasen
rejected Details | Review

Description Sebastien Bacher 2008-09-08 09:59:08 UTC
the bug has been opened on https://bugs.launchpad.net/bugs/236953

"When using gedit to browse a mounted sftp location for a file to open, or when browsing the sftp location to save a file, gedit will crash when using the breadcrumb (history) buttons to navigate.

How to replicate:

1) Add a bookmark to an ssh location which contains a couple of layers of directories
2) Open gedit and choose "File>Open..."
3) Click on the new bookmark and navigate down a directory tree a couple of levels
4) Use the breadcrumb buttons to go back to the top level of the bookmark
5) If gedit hasn't already crashed just navigate back and forth a couple of times using the buttons, it invariably does.

This also happens on "Save" and "Save As.." which can lead to losing work.

Updated 7th Sept 2008 to clarify and include steps to reproduce."
Comment 1 Sebastien Bacher 2008-09-08 10:03:08 UTC
ubuntu comments show those warnings:

"** (gedit:10379): WARNING **: Operation not supported by backend
gedit: ../../src/xcb_lock.c:77: _XGetXCBBuffer: Assertion `((int) ((xcb_req) - (dpy->request)) >= 0)' failed."

Comment 2 Paolo Borelli 2008-09-08 18:17:40 UTC
This seems now fixed by calling gdk_threads_init... gtkfilechooser user threads internally to interact with gtk, so even if gedit itself doesn't use threads the function is needed.
Comment 3 Paolo Borelli 2008-09-08 20:49:28 UTC
After some discussion or irc it turns out that calling gdk_threads_init is just a workaround, but the bug is really in gvfs that is calling callbacks from threads that are not the main thread.

The crash is triggered by the fact that gtk is trying to set the X cursor from multiple threads. This in turn is due from the fact that gvfs is running callback from the wrong threads.

The attached debugging patch for gtk shows it clearly and leads to the following stack trace:


Gtk-ERROR **: Unexpected call from a different thread
aborting...

Program received signal SIGABRT, Aborted.

Thread 3038239632 (LWP 27283)

  • #0 __kernel_vsyscall
  • #1 raise
    from /lib/tls/i686/cmov/libc.so.6
  • #2 abort
    from /lib/tls/i686/cmov/libc.so.6
  • #3 IA__g_logv
    at gmessages.c line 497
  • #4 IA__g_log
    at gmessages.c line 517
  • #5 set_busy_cursor
    at gtkfilechooserdefault.c line 6202
  • #6 update_current_folder_get_info_cb
    at gtkfilechooserdefault.c line 6833
  • #7 query_info_callback
    at gtkfilesystem.c line 772
  • #8 IA__g_simple_async_result_complete
    at gsimpleasyncresult.c line 554
  • #9 query_info_async_cb
    at gdaemonfile.c line 832
  • #10 async_path_call_done
    at gdaemonfile.c line 592
  • #11 async_call_finish
    at gvfsdaemondbus.c line 437
  • #12 handle_async_reply
    at gdbusutils.c line 1283
  • #13 _dbus_pending_call_complete
    at dbus-pending-call.c line 198
  • #14 complete_pending_call_and_unlock
    at dbus-connection.c line 2212
  • #15 dbus_connection_dispatch
    at dbus-connection.c line 4352
  • #16 _dbus_connection_read_write_dispatch
    at dbus-connection.c line 3431
  • #17 g_daemon_file_enumerator_next_file
    at gdaemonfileenumerator.c line 231
  • #18 next_files_thread
    at gfileenumerator.c line 640
  • #19 run_in_thread
    at gsimpleasyncresult.c line 614
  • #20 io_job_thread
    at gioscheduler.c line 179
  • #21 g_thread_pool_thread_proxy
    at gthreadpool.c line 265
  • #22 g_thread_create_proxy
    at gthread.c line 635
  • #23 start_thread
    from /lib/tls/i686/cmov/libpthread.so.0
  • #24 clone
    from /lib/tls/i686/cmov/libc.so.6


Here are some hints given on irc, but obviously it needs someone actually knowing that code to figure out the right fix...


<hp> the fix _could_ be changing g_simple_async_result_complete to g_simple_async_result_complete_in_idle
<hp> then again, it could not be that
<owen> Looks like that code should be changed to g_main_context_iteration() to me
<owen> that is, if you want to sleep for incoming messages in a thread, you need to just run the GLib main loop and let that pick up DBus messages and dispatch them
<owen> or maybe it needs ot be switched to a private connection
<owen> Or maybe the connection is private, and g_simple_async_result_complete_in_idle is the right answer :-)
<owen> Looks like the connectin is meant to be private
<owen> pbor: Anyways, I think if you put that stack trace in a gvfs bug report (or reassign the existing one) it should be easily fixable by someone who understands the gvfs code
<pbor> owen: yeah, I'll do that, thank you
<owen> I'ts clear that a lot of thought went into getting this right in gvfs, and there's just some leakage here
Comment 4 Paolo Borelli 2008-09-08 20:52:04 UTC
Created attachment 118328 [details] [review]
patch to point out the issue
Comment 5 Alexander Larsson 2008-09-11 08:13:08 UTC
Ah, this seems like a tricky issue.

The problem is in the implementation of the gvfs next_file() method in that it pumps the sync dbus connection to wait for incomming calls. However for the async emulation of this we do that in another thread than the one the sync dbus connection is for, so we reply to other dbus messages in the wrong thread.

I'll try to figure out a fix for this.
Comment 6 Matthias Clasen 2008-09-12 14:13:23 UTC
The easiest workaround for now will be to just make set_busy_cursor defer to an idle when called from those callbacks.
Comment 7 Paolo Borelli 2008-09-12 14:22:58 UTC
That doesn't sound very good to me: the fact that async gvfs calls run callback in the wrong thread will surely cause other bugs in other places and evry time it will be a PITA to reproduce and figure out.

We should really fix gvfs instead of patching this symptom
Comment 8 Matthias Clasen 2008-09-12 15:47:11 UTC
Created attachment 118595 [details] [review]
possible patch

Does this patch fix the crashes ?
Comment 9 Matthias Clasen 2008-09-12 15:54:26 UTC
Well, the filechooser code is a bit careless anyway. I'm pretty sure there are  places where set_busy_cursor is called outside the gdk lock, even with the gvfs problem fixed. 
Comment 10 Paolo Borelli 2008-09-13 09:29:24 UTC
I stll manage to make gedit (with the gdk_threads_init workaround removed) crash even with the patch applied. I get this:

Gtk:ERROR:gtkcontainer.c:2673:IA__gtk_container_propagate_expose: assertion failed: (child->parent == GTK_WIDGET (container))

Probably there are other things that do not like to be called from different threads beside set_busy_cursor (even if that one was prolly the most frequent, I took a bit more to get the crash now).


If you think that the patch is needed anyway, it looks ok to me... just a question (because I am a bit ignorant about main loop internals): when running the filechooser in a recursive main loop (modal), does g_source_attach (NULL) attach it to the inner main loop?
Comment 11 Matthias Clasen 2008-09-14 01:08:13 UTC
The docs say

It is possible to create new instances of GMainLoop recursively. This is often used in GTK+ applications when showing modal dialog boxes. Note that event sources are associated with a particular GMainContext, and will be checked and dispatched for all main loops associated with that GMainContext. 


It would be great to get a stacktrace from the crashes you still see.
Comment 12 Paolo Borelli 2008-09-14 10:01:29 UTC
Ok, here are the stack traces for crashes I managed to trigger even with the patch applied.
The second one is particularly interesting since it still crashing in set_busy_cursor, so it means there is something wrong with the patch.


sys:1: GtkWarning: gtk_tree_model_sort_convert_iter_to_child_iter: assertion `GTK_IS_TREE_MODEL_SORT (tree_model_sort)' failed

Program received signal SIGSEGV, Segmentation fault.

Thread 3070043904 (LWP 8684)

  • #0 __kernel_vsyscall
  • #1 raise
    from /lib/tls/i686/cmov/libc.so.6
  • #2 abort
    from /lib/tls/i686/cmov/libc.so.6
  • #3 IA__g_assertion_message
  • #4 IA__g_assertion_message_expr
  • #5 IA__gtk_container_propagate_expose
    at gtkcontainer.c line 2673
  • #6 gtk_container_expose_child
    at gtkcontainer.c line 2575
  • #7 gtk_path_bar_forall
    at gtkpathbar.c line 763
  • #8 IA__gtk_container_forall
    at gtkcontainer.c line 1455
  • #9 gtk_container_expose
    at gtkcontainer.c line 2598
  • #10 _gtk_marshal_BOOLEAN__BOXED
    at gtkmarshalers.c line 84
  • #11 g_type_class_meta_marshal
    at gclosure.c line 878
  • #12 IA__g_closure_invoke
    at gclosure.c line 767
  • #13 signal_emit_unlocked_R
    at gsignal.c line 3282
  • #14 IA__g_signal_emit_valist
    at gsignal.c line 2987
  • #15 IA__g_signal_emit
    at gsignal.c line 3034
  • #16 gtk_widget_event_internal
    at gtkwidget.c line 4745
  • #17 IA__gtk_widget_send_expose
    at gtkwidget.c line 4574
  • #18 IA__gtk_container_propagate_expose
  • #19 gtk_container_expose_child
    at gtkcontainer.c line 2575
  • #20 gtk_box_forall
    at gtkbox.c line 783
  • #21 IA__gtk_container_forall
    at gtkcontainer.c line 1455
  • #22 gtk_container_expose
    at gtkcontainer.c line 2598
  • #23 _gtk_marshal_BOOLEAN__BOXED
    at gtkmarshalers.c line 84
  • #24 g_type_class_meta_marshal
    at gclosure.c line 878
  • #25 IA__g_closure_invoke
    at gclosure.c line 767
  • #26 signal_emit_unlocked_R
    at gsignal.c line 3282
  • #27 IA__g_signal_emit_valist
    at gsignal.c line 2987
  • #28 IA__g_signal_emit
    at gsignal.c line 3034
  • #29 gtk_widget_event_internal
    at gtkwidget.c line 4745
  • #30 IA__gtk_widget_send_expose
    at gtkwidget.c line 4574
  • #31 IA__gtk_container_propagate_expose
    at gtkcontainer.c line 2687
  • #32 gtk_container_expose_child
    at gtkcontainer.c line 2575
  • #33 gtk_box_forall
    at gtkbox.c line 783
  • #34 IA__gtk_container_forall
    at gtkcontainer.c line 1455
  • #35 gtk_container_expose
    at gtkcontainer.c line 2598
  • #36 _gtk_marshal_BOOLEAN__BOXED
    at gtkmarshalers.c line 84
  • #37 g_type_class_meta_marshal
    at gclosure.c line 878
  • #38 IA__g_closure_invoke
    at gclosure.c line 767
  • #39 signal_emit_unlocked_R
    at gsignal.c line 3282
  • #40 IA__g_signal_emit_valist
    detail=0, var_args=0xbfa8aed0 "
Comment 13 Alexander Larsson 2008-09-14 18:00:34 UTC
I know what the core problem and the fix is, I'll try to schedule some time tomorrow to write the fix.
Comment 14 André Klapper 2008-09-14 18:03:50 UTC
...would be great because HardCode Freeze is tomorrow (Monday 23:59 UTC).
Comment 15 Alexander Larsson 2008-09-15 09:33:59 UTC
2008-09-15  Alexander Larsson  <alexl@redhat.com>

        * client/gdaemonfile.c:
        * client/gdaemonfileenumerator.c:
	Add proper implementation of async file enumeration.
	This avoids the problem with the default thread based ones
	that could cause callbacks in the non-mainloop thread. (#551337)

Checked in on the 2.24 branch. It fixes the problem for me. Could you also test it?
Comment 16 Paolo Borelli 2008-09-15 10:27:03 UTC
I couldn't get the filechooser to crash with the updated gvfs. Thanks Alex.

Maybe it's worth adding a unit test that checks if the callback is run in the main thread? Just a thought...
Comment 17 Alexander Larsson 2008-09-15 11:38:17 UTC
paolo: 

Its kinda hard to trigger the case where this would happen as its somewhat of a race. So the unit test might not be so easy to write.
Comment 18 Matthias Clasen 2008-09-16 16:41:35 UTC
Moving back to gtk for remaining possible set_busy_cursor issues
Comment 19 Federico Mena Quintero 2009-01-23 02:11:54 UTC
I checked gtkfilesystem.c and all the invocations of user callbacks are wrapped with gdk_threads_enter/leave().

I checked gtkfilechooserdefault.c to see where set_busy_cursor() is called, and it's random functions or those async callbacks that do the wrapping.

Can we close this now?
Comment 20 Fabio Durán Verdugo 2010-11-25 03:56:11 UTC
(In reply to comment #19)
> I checked gtkfilesystem.c and all the invocations of user callbacks are wrapped
> with gdk_threads_enter/leave().
> 
> I checked gtkfilechooserdefault.c to see where set_busy_cursor() is called, and
> it's random functions or those async callbacks that do the wrapping.
> 
> Can we close this now?

can we close?
Comment 21 Federico Mena Quintero 2010-11-25 17:37:03 UTC
Let's close!