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 777808 - Deadlock in g_cancellable_disconnect()
Deadlock in g_cancellable_disconnect()
Status: RESOLVED FIXED
Product: libgovirt
Classification: Other
Component: general
unspecified
Other Linux
: Normal normal
: ---
Assigned To: libgovirt maintainer(s)
Depends on:
Blocks:
 
 
Reported: 2017-01-26 20:20 UTC by Eduardo Lima (Etrunko)
Modified: 2017-04-11 09:31 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
gdb backrace (17.67 KB, text/plain)
2017-01-26 20:20 UTC, Eduardo Lima (Etrunko)
  Details
Proposed fix (2.67 KB, patch)
2017-01-26 20:21 UTC, Eduardo Lima (Etrunko)
none Details | Review
Alternate solution (2.36 KB, patch)
2017-01-27 12:21 UTC, Eduardo Lima (Etrunko)
none Details | Review
Hold reference to cancellable object (1.52 KB, patch)
2017-02-02 17:19 UTC, Eduardo Lima (Etrunko)
accepted-commit_now Details | Review
Check if operation is cancelled before disconnecting signal (1.88 KB, patch)
2017-02-02 17:20 UTC, Eduardo Lima (Etrunko)
accepted-commit_now Details | Review

Description Eduardo Lima (Etrunko) 2017-01-26 20:20:46 UTC
Created attachment 344353 [details]
gdb backrace

When user passes a GCancellable object to the async operation and calls g_cancellable_cancel() for any reason, it will cause a deadlock. A recent patch to virt-viewer[1] exposes this problem, but luckily this situation is already documented[2]

[1] https://www.redhat.com/archives/virt-tools-list/2017-January/msg00126.html
[2] https://developer.gnome.org/gio/stable/GCancellable.html#g-cancellable-disconnect.
Comment 1 Eduardo Lima (Etrunko) 2017-01-26 20:21:38 UTC
Created attachment 344354 [details] [review]
Proposed fix
Comment 2 Christophe Fergeau 2017-01-27 10:15:24 UTC
Review of attachment 344354 [details] [review]:

::: govirt/ovirt-proxy.c
@@ +217,3 @@
         }
         if ((data->cancellable != NULL) && (data->cancellable_cb_id != 0)) {
             g_cancellable_disconnect(data->cancellable, data->cancellable_cb_id);

I'm wondering if not using an idle, but instead doing this would work:

        if ((data->cancellable != NULL) && (data->cancellable_cb_id != 0)) {
            if (g_cancellable_is_cancelled(data->cancellable)) {
                /* Cancellable has already been cancelled, we don't need to use
                 * g_cancellable_disconnect() to disconnect the signal handler
                 * as we know the 'cancelled' signal is no longer going to be emitted
                 */
                g_signal_handler_disconnect(data->cancellable, data->cancellable_cb_id);
            } else {
                g_cancellable_disconnect(data->cancellable, data->cancellable_cb_id);
            }
        }

@@ +218,3 @@
         if ((data->cancellable != NULL) && (data->cancellable_cb_id != 0)) {
             g_cancellable_disconnect(data->cancellable, data->cancellable_cb_id);
+            g_clear_object(&data->cancellable);

data->cancellable is leaked when it's not NULL but data->cancellable_cb_id is 0. You can move the g_clear_object outside of the if(), this should work juste fine.

@@ +266,3 @@
+     * avoid this
+     */
+    g_idle_add(ovirt_proxy_call_async_data_free, data);

Looking a bit at code using GCancellable, there might be an alternative way.

@@ +292,3 @@
     data->destroy_call_data = destroy_func;
     if (cancellable != NULL) {
+        data->cancellable = g_object_ref(cancellable);

Imo this part makes sense regardless of how we fix the deadlock
Comment 3 Eduardo Lima (Etrunko) 2017-01-27 12:16:30 UTC
I have just tried this new version without using idle and it works. Which one would be the best?
Comment 4 Eduardo Lima (Etrunko) 2017-01-27 12:21:16 UTC
Created attachment 344407 [details] [review]
Alternate solution

Disregard the commit message by the way.
Comment 5 Christophe Fergeau 2017-01-30 15:08:14 UTC
(In reply to Eduardo Lima (Etrunko) from comment #3)
> I have just tried this new version without using idle and it works. Which
> one would be the best?

I prefer the alternate solution.
Comment 6 Christophe Fergeau 2017-01-30 15:09:19 UTC
Review of attachment 344407 [details] [review]:

::: govirt/ovirt-proxy.c
@@ +292,3 @@
     data->destroy_call_data = destroy_func;
     if (cancellable != NULL) {
+        data->cancellable = g_object_ref(cancellable);

I don't think this belongs to this patch (ie the patch should work even without this ?)
Comment 7 Eduardo Lima (Etrunko) 2017-01-31 18:29:38 UTC
(In reply to Christophe Fergeau from comment #6)
> Review of attachment 344407 [details] [review] [review]:
> 
> ::: govirt/ovirt-proxy.c
> @@ +292,3 @@
>      data->destroy_call_data = destroy_func;
>      if (cancellable != NULL) {
> +        data->cancellable = g_object_ref(cancellable);
> 
> I don't think this belongs to this patch (ie the patch should work even
> without this ?)

Hmm, from your previous comments, I understood that it would make sense to hold the reference to the cancellable either way.
Comment 8 Christophe Fergeau 2017-02-02 08:06:18 UTC
It makes sense, it was needed in the first version iirc. In the second version, I don't think it's required. But regardless of the patch, it makes sense yes, just not sure we should have this change squashed in this ptach.
Comment 9 Eduardo Lima (Etrunko) 2017-02-02 12:32:11 UTC
(In reply to Christophe Fergeau from comment #8)
> It makes sense, it was needed in the first version iirc. In the second
> version, I don't think it's required. But regardless of the patch, it makes
> sense yes, just not sure we should have this change squashed in this ptach.

Alright, I will split those patches and submit. Thanks for the review.
Comment 10 Eduardo Lima (Etrunko) 2017-02-02 17:19:37 UTC
Created attachment 344796 [details] [review]
Hold reference to cancellable object
Comment 11 Eduardo Lima (Etrunko) 2017-02-02 17:20:07 UTC
Created attachment 344797 [details] [review]
Check if operation is cancelled before disconnecting signal
Comment 12 Christophe Fergeau 2017-04-11 09:31:42 UTC
This was pushed a while ago.