From 340b52fbeec4ae2ba7f8f70d270efc6440ec91fe Mon Sep 17 00:00:00 2001
From: George Kiagiadakis <george.kiagiadakis@collabora.com>
Date: Tue, 17 Sep 2019 16:19:13 +0300
Subject: [PATCH] proxy: fix crash that happens when a client exits very
 quickly after starting

This is very easy to reproduce when the pipewire-alsa integration
is installed and you do 'arecord -l'; the alsa plugin connects and
disconnects again before the proxy is ready.

In this case we have to skip remote-global-added and we also have
to be careful with the references: the global-removed callback is
called earlier, so the core's reference to the proxy is gone and
the GTask is the only thing holding a reference to the proxy.
When we unref the GTask, the proxy is also unrefed, so we have
to keep an additional reference in order to avoid crashing
when accessing the hash table below.
---
 lib/wp/core.c  |  1 +
 lib/wp/proxy.c | 10 ++++++----
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/lib/wp/core.c b/lib/wp/core.c
index c114936b..d065741c 100644
--- a/lib/wp/core.c
+++ b/lib/wp/core.c
@@ -138,6 +138,7 @@ on_proxy_ready (GObject * obj, GAsyncResult * res, gpointer data)
 
   if (!wp_proxy_augment_finish (proxy, res, &error)) {
     g_warning ("Failed to augment WpProxy (%p): %s", obj, error->message);
+    return;
   }
 
   g_signal_emit (self, signals[SIGNAL_REMOTE_GLOBAL_ADDED],
diff --git a/lib/wp/proxy.c b/lib/wp/proxy.c
index 16c8b205..876a721d 100644
--- a/lib/wp/proxy.c
+++ b/lib/wp/proxy.c
@@ -130,7 +130,9 @@ wp_proxy_find_quark_for_type (guint32 type)
 static void
 proxy_event_destroy (void *data)
 {
-  WpProxy *self = WP_PROXY (data);
+  /* hold a reference to the proxy because unref-ing the tasks might
+    destroy the proxy, in case the core is no longer holding a reference */
+  g_autoptr (WpProxy) self = g_object_ref (WP_PROXY (data));
   WpProxyPrivate *priv = wp_proxy_get_instance_private (self);
   GHashTableIter iter;
   GTask *task;
@@ -144,7 +146,7 @@ proxy_event_destroy (void *data)
   if (priv->task) {
     g_task_return_new_error (priv->task, WP_DOMAIN_LIBRARY,
         WP_LIBRARY_ERROR_OPERATION_FAILED,
-        "pipewire node proxy destroyed before finishing");
+        "pipewire proxy destroyed before finishing");
     g_clear_object (&priv->task);
   }
 
@@ -152,7 +154,7 @@ proxy_event_destroy (void *data)
   while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &task)) {
     g_task_return_new_error (task, WP_DOMAIN_LIBRARY,
         WP_LIBRARY_ERROR_OPERATION_FAILED,
-        "pipewire node proxy destroyed before finishing");
+        "pipewire proxy destroyed before finishing");
     g_hash_table_iter_remove (&iter);
   }
 }
@@ -218,9 +220,9 @@ wp_proxy_finalize (GObject * object)
   g_debug ("%s:%p destroyed (global %u; pw_proxy %p)",
       G_OBJECT_TYPE_NAME (object), object, priv->global_id, priv->pw_proxy);
 
+  g_clear_pointer (&priv->pw_proxy, pw_proxy_destroy);
   g_clear_object (&priv->task);
   g_clear_pointer (&priv->global_props, wp_properties_unref);
-  g_clear_pointer (&priv->pw_proxy, pw_proxy_destroy);
   g_weak_ref_clear (&priv->core);
   g_clear_pointer (&priv->async_tasks, g_hash_table_unref);
 
-- 
GitLab