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 745013 - GBinding not thread safe
GBinding not thread safe
Status: RESOLVED OBSOLETE
Product: glib
Classification: Platform
Component: gobject
2.42.x
Other Linux
: Normal critical
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2015-02-23 13:36 UTC by Pacho Ramos
Modified: 2018-05-24 17:29 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Full trace (157.88 KB, text/plain)
2015-02-23 13:37 UTC, Pacho Ramos
  Details
Offending mail (66.18 KB, text/plain)
2015-02-23 13:47 UTC, Pacho Ramos
  Details
mail.mbox (22.51 KB, text/plain)
2015-02-23 13:58 UTC, Pacho Ramos
  Details
binding: Remove GObject data usage (4.13 KB, patch)
2015-06-04 00:17 UTC, Garrett Regier
committed Details | Review

Description Pacho Ramos 2015-02-23 13:36:53 UTC
I simply pressed Ctrl+d to remove a mail and evolution crashed:

Core was generated by `evolution'.
Program terminated with signal SIGABRT, Aborted.

Thread 36 (Thread 0x7fc3998c6940 (LWP 30961))

  • #0 ??
    from /lib64/libc.so.6
  • #1 readdir64
    from /lib64/libc.so.6
  • #2 g_dir_read_name
    at /var/tmp/portage/dev-libs/glib-2.42.1/work/glib-2.42.1/glib/gdir.c line 287
  • #3 data_cache_expire
    at camel-data-cache.c line 289
  • #4 data_cache_path
    at camel-data-cache.c line 345
  • #5 camel_data_cache_get_filename
    at camel-data-cache.c line 486
  • #6 mail_display_image_exists_in_cache
    at e-mail-display.c line 165
  • #7 mail_display_redirect_uri
    at e-mail-display.c line 1307
  • #8 mail_display_resource_requested
    at e-mail-display.c line 303
  • #9 g_closure_invoke
    at /var/tmp/portage/dev-libs/glib-2.42.1/work/glib-2.42.1/gobject/gclosure.c line 768
  • #10 signal_emit_unlocked_R
    at /var/tmp/portage/dev-libs/glib-2.42.1/work/glib-2.42.1/gobject/gsignal.c line 3553
  • #11 g_signal_emit_valist
    at /var/tmp/portage/dev-libs/glib-2.42.1/work/glib-2.42.1/gobject/gsignal.c line 3309
  • #12 g_signal_emit_by_name
    at /var/tmp/portage/dev-libs/glib-2.42.1/work/glib-2.42.1/gobject/gsignal.c line 3405
  • #13 WebKit::FrameLoaderClient::dispatchWillSendRequest
    at Source/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.cpp line 258
  • #14 WebCore::ResourceLoadNotifier::dispatchWillSendRequest
    at Source/WebCore/loader/ResourceLoadNotifier.cpp line 133
  • #15 WebCore::ResourceLoadNotifier::willSendRequest
    at Source/WebCore/loader/ResourceLoadNotifier.cpp line 78
  • #16 WebCore::ResourceLoader::willSendRequest
    at Source/WebCore/loader/ResourceLoader.cpp line 273
  • #17 WebCore::SubresourceLoader::willSendRequest
    at Source/WebCore/loader/SubresourceLoader.cpp line 177
  • #18 WebCore::ResourceLoader::init
    at Source/WebCore/loader/ResourceLoader.cpp line 140
  • #19 WebCore::SubresourceLoader::init
    at Source/WebCore/loader/SubresourceLoader.cpp line 132
  • #20 WebCore::SubresourceLoader::create
    at Source/WebCore/loader/SubresourceLoader.cpp line 100
  • #21 WebCore::ResourceLoadScheduler::scheduleSubresourceLoad
    at Source/WebCore/loader/ResourceLoadScheduler.cpp line 113
  • #22 WebCore::CachedResource::load
    at Source/WebCore/loader/cache/CachedResource.cpp line 316
  • #23 WebCore::CachedResourceLoader::requestResource
    at Source/WebCore/loader/cache/CachedResourceLoader.cpp line 467
  • #24 WebCore::CachedResourceLoader::requestImage
    at Source/WebCore/loader/cache/CachedResourceLoader.cpp line 163
  • #25 WebCore::ImageLoader::updateFromElement
    at Source/WebCore/loader/ImageLoader.cpp line 201
  • #26 WebCore::HTMLImageElement::parseAttribute
    at Source/WebCore/html/HTMLImageElement.cpp line 122
  • #27 WebCore::Element::attributeChanged
    at Source/WebCore/dom/Element.cpp line 1094
  • #28 WebCore::Element::parserSetAttributes
    at Source/WebCore/dom/Element.cpp line 1274
  • #29 setAttributes
    at Source/WebCore/html/parser/HTMLConstructionSite.cpp line 55
  • #30 WebCore::HTMLConstructionSite::createHTMLElement
    at Source/WebCore/html/parser/HTMLConstructionSite.cpp line 639
  • #31 WebCore::HTMLConstructionSite::insertSelfClosingHTMLElement
    at Source/WebCore/html/parser/HTMLConstructionSite.cpp line 480
  • #32 WebCore::HTMLTreeBuilder::processStartTagForInBody
    at Source/WebCore/html/parser/HTMLTreeBuilder.cpp line 826
  • #33 WebCore::HTMLTreeBuilder::processStartTag
    at Source/WebCore/html/parser/HTMLTreeBuilder.cpp line 1195
  • #34 WebCore::HTMLTreeBuilder::processToken
    at Source/WebCore/html/parser/HTMLTreeBuilder.cpp line 401
  • #35 WebCore::HTMLTreeBuilder::constructTree
    at Source/WebCore/html/parser/HTMLTreeBuilder.cpp line 373
  • #36 WebCore::HTMLDocumentParser::constructTreeFromHTMLToken
    at Source/WebCore/html/parser/HTMLDocumentParser.cpp line 352
  • #37 WebCore::HTMLDocumentParser::pumpTokenizer
    at Source/WebCore/html/parser/HTMLDocumentParser.cpp line 309
  • #38 WebCore::HTMLDocumentParser::append
    at Source/WebCore/html/parser/HTMLDocumentParser.cpp line 428
  • #39 WebCore::DecodedDataDocumentParser::appendBytes
    at Source/WebCore/dom/DecodedDataDocumentParser.cpp line 50
  • #40 WebCore::DocumentLoader::commitData
    at Source/WebCore/loader/DocumentLoader.cpp line 843
  • #41 WebKit::FrameLoaderClient::committedLoad
    at Source/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.cpp line 165
  • #42 WebCore::DocumentLoader::commitLoad
    at Source/WebCore/loader/DocumentLoader.cpp line 773
  • #43 WebCore::CachedRawResource::notifyClientsDataWasReceived
    at Source/WebCore/loader/cache/CachedRawResource.cpp line 110
  • #44 WebCore::CachedRawResource::addDataBuffer
    at Source/WebCore/loader/cache/CachedRawResource.cpp line 66
  • #45 WebCore::SubresourceLoader::didReceiveDataOrBuffer
    at Source/WebCore/loader/SubresourceLoader.cpp line 274
  • #46 WebCore::SubresourceLoader::didReceiveBuffer
    at Source/WebCore/loader/SubresourceLoader.cpp line 255
  • #47 WebCore::ResourceLoader::didReceiveBuffer
    at Source/WebCore/loader/ResourceLoader.cpp line 511
  • #48 WebCore::readCallback
    at Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp line 1352
  • #49 async_ready_callback_wrapper
    at /var/tmp/portage/dev-libs/glib-2.42.1/work/glib-2.42.1/gio/ginputstream.c line 523
  • #50 g_task_return_now
    at /var/tmp/portage/dev-libs/glib-2.42.1/work/glib-2.42.1/gio/gtask.c line 1077
  • #51 complete_in_idle_cb
    at /var/tmp/portage/dev-libs/glib-2.42.1/work/glib-2.42.1/gio/gtask.c line 1086
  • #52 g_main_dispatch
    at /var/tmp/portage/dev-libs/glib-2.42.1/work/glib-2.42.1/glib/gmain.c line 3111
  • #53 g_main_context_dispatch
    at /var/tmp/portage/dev-libs/glib-2.42.1/work/glib-2.42.1/glib/gmain.c line 3710
  • #54 g_main_context_iterate
    at /var/tmp/portage/dev-libs/glib-2.42.1/work/glib-2.42.1/glib/gmain.c line 3781
  • #55 g_main_loop_run
    at /var/tmp/portage/dev-libs/glib-2.42.1/work/glib-2.42.1/glib/gmain.c line 3975
  • #56 gtk_main
    at /var/tmp/portage/x11-libs/gtk+-3.14.8/work/gtk+-3.14.8/gtk/gtkmain.c line 1207
  • #57 main
    at main.c line 685

Thread 30 (Thread 0x7fc2ba7fc700 (LWP 26172)):
Comment 1 Pacho Ramos 2015-02-23 13:37:50 UTC
Created attachment 297641 [details]
Full trace
Comment 2 Pacho Ramos 2015-02-23 13:47:21 UTC
Created attachment 297642 [details]
Offending mail
Comment 3 Pacho Ramos 2015-02-23 13:49:56 UTC
Comment on attachment 297642 [details]
Offending mail

Umm... no, that is not the mail... I am searching still
Comment 4 Pacho Ramos 2015-02-23 13:58:01 UTC
Created attachment 297645 [details]
mail.mbox
Comment 5 Milan Crha 2015-02-23 17:44:26 UTC
Thanks for a bug report. Looking into the full backtrace I see that Thread 2 and Thread 1 are both accessing the same GHashTable at once. Both are inserting into the hash table (modifying its content).

It's GLib / GBinding issue, thus I move this there.
Comment 6 Emmanuele Bassi (:ebassi) 2015-02-23 17:56:30 UTC
The GHashTable is retrieved using qdata, which should be thread safe, but the access inside the hash table itself is not thread safe. To be honest, we never said that bindings are thread safe; we could specify it into the documentation, but maybe we can do better.
Comment 7 Milan Crha 2015-02-23 19:16:14 UTC
Please do better. If you look into the full backtrace, on those two threads, then you'll see that no application has any real way of adding thread safety on its own. Maybe only if it'll avoid usage of GBinding all together or ..., I do not know, I do not want to sound silly. I just believe that the thread safety will be beneficial for any GLib users.
Comment 8 Emmanuele Bassi (:ebassi) 2015-02-23 19:43:06 UTC
Looking at the issue some more, and it's not an entirely trivial issue that would be solved by locking the hash table when adding the binding data to the source and target.

In the strictest sense, the issue is that two threads are trying to create a 
binding on the same instance; what happens is that:

  * we retrieve the set of bindings associated with an instance from its qdata
  * if there is no set, we create one and add it to the instance's qdata
  * we add the GBinding instance to the set

We would need to "lock" the instance while we do this, because while retrieving the bindings set from the qdata and setting it are safe operations (the GData is accessed atomically or under a lock), multiple threads could try to add different GHashTable instances.

We don't have any mechanism inside GObject to say "please, lock this instance while I do stuff", and even if we did, it would very likely interfere with custom property setter/getter code. Creating a binding inside a thread means that the property setter and getter on both the source and the target need to be thread safe, because, for instance, SYNC_CREATE will cause the property on the source instance to be retrieved, and some value to be set on the target instance.

We may need something similar to GWeakRef associated to the GBinding instances.
Comment 9 Milan Crha 2015-02-24 07:45:07 UTC
Okay. I checked the related code in evolution and it was the only GBinding usage in that function, a direct usage, thus I replaced it with simple get&set of a property, which might be sufficient in this case. That was done with commit_36776ba in evo master (3.15.91+) [1]. It doesn't fix general issue with thread unsafe GBinding usage, only this concrete place in evolution.

[1] https://git.gnome.org/browse/evolution/commit/?id=36776ba
Comment 10 Milan Crha 2015-02-24 09:03:41 UTC
(In reply to Milan Crha from comment #9)
> That was done with commit_36776ba in evo master (3.15.91+) [1]. It doesn't
> fix general issue with thread unsafe GBinding usage, only this concrete
> place in evolution.

I dived deeper into this and added thread safe variants of the g_object_bind_property*() functions into evolution-data-server and use them across the projects. The thread safety is added by a lock on the whole function call, which might help in this case too. Most of the places in evolution are related to widgets, thus it's all done in the main thread, but I wanted to be consistent, thus I replaced the calls also there.

It would be still good to (somehow) add thread safety into GBinding itself, because my proxy functions do not cover binding removals.
Comment 11 Garrett Regier 2015-06-04 00:17:18 UTC
Created attachment 304559 [details] [review]
binding: Remove GObject data usage

It isn't actually doing anything, instead it is being managed without actually being used. This has the result that GBinding is now more
thread-safe.
Comment 12 Emmanuele Bassi (:ebassi) 2015-06-04 00:44:13 UTC
Review of attachment 304559 [details] [review]:

The idea behind storing the GBinding instances inside a GHashTable associated with the source/target GObject instance was to have API that let you query whether or not a GObject has bindings, and eventually access each binding to let you either query it or remove it. I never committed it because I didn't know if it would be used, and I didn't want to overcomplicate it.

After 5 years nobody asked for it, so I guess we could simply ignore it, and remove it.

It won't really make GBinding thread safe, though: we use g_object_weak_ref()/unref(), and the code would need to be switched to GWeakRef.
Comment 13 Emmanuele Bassi (:ebassi) 2015-06-04 00:44:14 UTC
Review of attachment 304559 [details] [review]:

The idea behind storing the GBinding instances inside a GHashTable associated with the source/target GObject instance was to have API that let you query whether or not a GObject has bindings, and eventually access each binding to let you either query it or remove it. I never committed it because I didn't know if it would be used, and I didn't want to overcomplicate it.

After 5 years nobody asked for it, so I guess we could simply ignore it, and remove it.

It won't really make GBinding thread safe, though: we use g_object_weak_ref()/unref(), and the code would need to be switched to GWeakRef.
Comment 14 Emmanuele Bassi (:ebassi) 2015-06-04 00:44:14 UTC
Review of attachment 304559 [details] [review]:

The idea behind storing the GBinding instances inside a GHashTable associated with the source/target GObject instance was to have API that let you query whether or not a GObject has bindings, and eventually access each binding to let you either query it or remove it. I never committed it because I didn't know if it would be used, and I didn't want to overcomplicate it.

After 5 years nobody asked for it, so I guess we could simply ignore it, and remove it.

It won't really make GBinding thread safe, though: we use g_object_weak_ref()/unref(), and the code would need to be switched to GWeakRef.
Comment 15 Garrett Regier 2015-06-04 00:48:21 UTC
Comment on attachment 304559 [details] [review]
binding: Remove GObject data usage

Thanks for the crazy fast reviews!
Comment 16 Milan Crha 2015-06-29 05:59:44 UTC
(In reply to Garrett Regier from comment #15)
> Comment on attachment 304559 [details] [review] [review]
> binding: Remove GObject data usage
> 
> Thanks for the crazy fast reviews!

Could you push it into the stable version too, please? I've just got a crash report [1] from the functions you removed, thus it makes sense to cover it in stable as well.

[1] https://bugzilla.redhat.com/show_bug.cgi?id=1236293
Comment 17 GNOME Infrastructure Team 2018-05-24 17:29:39 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to GNOME's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/glib/issues/996.