Blame SOURCES/0028-channel-main-Use-heap-and-reference-counting-for-spi.patch

542743
From 8f1147b4119f920b69eb9c577121cbd5ac1e1d70 Mon Sep 17 00:00:00 2001
542743
From: Frediano Ziglio <freddy77@gmail.com>
542743
Date: Mon, 10 Aug 2020 15:27:09 +0100
542743
Subject: [PATCH 28/31] channel-main: Use heap and reference counting for
542743
 spice_migrate
542743
542743
Don't use the stack, it will potentially disappear (see mig
542743
variable in main_migrate_connect).
542743
For instance channels use this structure when they are freed. As
542743
the free is done in delayed mode the initial coroutine could be
542743
ended releasing the stack and causing a segmentation fault.
542743
542743
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=1867564.
542743
542743
Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
542743
Acked-by: Uri Lublin <uril@redhat.com>
542743
---
542743
 src/channel-main.c | 110 ++++++++++++++++++++++++++++++++-------------
542743
 1 file changed, 78 insertions(+), 32 deletions(-)
542743
542743
diff --git a/src/channel-main.c b/src/channel-main.c
542743
index 79fe63c..8caf727 100644
542743
--- a/src/channel-main.c
542743
+++ b/src/channel-main.c
542743
@@ -123,6 +123,7 @@ struct spice_migrate {
542743
     struct coroutine *from;
542743
     SpiceMigrationDstInfo *info;
542743
     SpiceSession *session;
542743
+    int ref_count;
542743
     guint nchannels;
542743
     SpiceChannel *src_channel;
542743
     SpiceChannel *dst_channel;
542743
@@ -175,8 +176,8 @@ static void channel_set_handlers(SpiceChannelClass *klass);
542743
 static void agent_send_msg_queue(SpiceMainChannel *channel);
542743
 static void agent_free_msg_queue(SpiceMainChannel *channel);
542743
 static void migrate_channel_event_cb(SpiceChannel *channel, SpiceChannelEvent event,
542743
-                                     gpointer data);
542743
-static gboolean main_migrate_handshake_done(gpointer data);
542743
+                                     spice_migrate *mig);
542743
+static gboolean main_migrate_handshake_done(spice_migrate *mig);
542743
 static void spice_main_channel_send_migration_handshake(SpiceChannel *channel);
542743
 static void file_xfer_flushed(SpiceMainChannel *channel, gboolean success);
542743
 static void file_xfer_read_async_cb(GObject *source_object,
542743
@@ -193,6 +194,7 @@ static void file_transfer_operation_task_finished(SpiceFileTransferTask *xfer_ta
542743
                                                   GError *error,
542743
                                                   gpointer userdata);
542743
 static void file_transfer_operation_send_progress(SpiceFileTransferTask *xfer_task);
542743
+static void spice_migrate_unref(spice_migrate *mig);
542743
 
542743
 /* ------------------------------------------------------------------ */
542743
 
542743
@@ -387,6 +389,7 @@ static void spice_main_channel_finalize(GObject *obj)
542743
 {
542743
     SpiceMainChannelPrivate *c = SPICE_MAIN_CHANNEL(obj)->priv;
542743
 
542743
+    spice_migrate_unref(c->migrate_data);
542743
     g_free(c->agent_msg_data);
542743
     agent_free_msg_queue(SPICE_MAIN_CHANNEL(obj));
542743
 
542743
@@ -2242,11 +2245,50 @@ static void main_handle_agent_token(SpiceChannel *channel, SpiceMsgIn *in)
542743
     agent_send_msg_queue(SPICE_MAIN_CHANNEL(channel));
542743
 }
542743
 
542743
+static spice_migrate*
542743
+spice_migrate_ref(spice_migrate *mig)
542743
+{
542743
+    if (mig != NULL) {
542743
+        mig->ref_count++;
542743
+    }
542743
+    return mig;
542743
+}
542743
+
542743
+static void
542743
+spice_migrate_unref(spice_migrate *mig)
542743
+{
542743
+    if (mig != NULL && --mig->ref_count == 0) {
542743
+        g_free(mig);
542743
+    }
542743
+}
542743
+
542743
+static inline void
542743
+spice_migrate_idle_add(gboolean (*func)(spice_migrate *mig), spice_migrate *mig)
542743
+{
542743
+    g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) func, spice_migrate_ref(mig),
542743
+                    (GDestroyNotify) spice_migrate_unref);
542743
+}
542743
+
542743
+static void
542743
+spice_migrate_closure_unref(spice_migrate *mig, GClosure *closure)
542743
+{
542743
+    spice_migrate_unref(mig);
542743
+}
542743
+
542743
+static gulong
542743
+spice_migrate_signal_connect(gpointer instance, const gchar *detailed_signal,
542743
+                             GCallback func, spice_migrate *mig)
542743
+{
542743
+    return g_signal_connect_data(instance, detailed_signal, func, spice_migrate_ref(mig),
542743
+                                 (GClosureNotify) spice_migrate_closure_unref,
542743
+                                 (GConnectFlags) 0);
542743
+}
542743
+
542743
 /* main context */
542743
-static void migrate_channel_new_cb(SpiceSession *s, SpiceChannel *channel, gpointer data)
542743
+static void migrate_channel_new_cb(SpiceSession *s, SpiceChannel *channel, spice_migrate *mig)
542743
 {
542743
-    g_signal_connect(channel, "channel-event",
542743
-                     G_CALLBACK(migrate_channel_event_cb), data);
542743
+    spice_migrate_signal_connect(channel, "channel-event",
542743
+                                 G_CALLBACK(migrate_channel_event_cb), mig);
542743
 }
542743
 
542743
 static void
542743
@@ -2267,7 +2309,7 @@ static void spice_main_channel_send_migration_handshake(SpiceChannel *channel)
542743
 
542743
     if (!spice_channel_test_capability(channel, SPICE_MAIN_CAP_SEAMLESS_MIGRATE)) {
542743
         c->migrate_data->do_seamless = false;
542743
-        g_idle_add(main_migrate_handshake_done, c->migrate_data);
542743
+        spice_migrate_idle_add(main_migrate_handshake_done, c->migrate_data);
542743
     } else {
542743
         SpiceMsgcMainMigrateDstDoSeamless msg_data;
542743
         SpiceMsgOut *msg_out;
542743
@@ -2282,13 +2324,12 @@ static void spice_main_channel_send_migration_handshake(SpiceChannel *channel)
542743
 
542743
 /* main context */
542743
 static void migrate_channel_event_cb(SpiceChannel *channel, SpiceChannelEvent event,
542743
-                                     gpointer data)
542743
+                                     spice_migrate *mig)
542743
 {
542743
-    spice_migrate *mig = data;
542743
     SpiceChannelPrivate  *c = SPICE_CHANNEL(channel)->priv;
542743
 
542743
     g_return_if_fail(mig->nchannels > 0);
542743
-    g_signal_handlers_disconnect_by_func(channel, migrate_channel_event_cb, data);
542743
+    g_signal_handlers_disconnect_by_func(channel, migrate_channel_event_cb, mig);
542743
 
542743
     switch (event) {
542743
     case SPICE_CHANNEL_OPENED:
542743
@@ -2299,7 +2340,8 @@ static void migrate_channel_event_cb(SpiceChannel *channel, SpiceChannelEvent ev
542743
 
542743
                 c->state = SPICE_CHANNEL_STATE_MIGRATION_HANDSHAKE;
542743
                 mig->dst_channel = channel;
542743
-                main_priv->migrate_data = mig;
542743
+                spice_migrate_unref(main_priv->migrate_data);
542743
+                main_priv->migrate_data = spice_migrate_ref(mig);
542743
             } else {
542743
                 c->state = SPICE_CHANNEL_STATE_MIGRATING;
542743
                 mig->nchannels--;
542743
@@ -2332,9 +2374,8 @@ static void migrate_channel_event_cb(SpiceChannel *channel, SpiceChannelEvent ev
542743
 }
542743
 
542743
 /* main context */
542743
-static gboolean main_migrate_handshake_done(gpointer data)
542743
+static gboolean main_migrate_handshake_done(spice_migrate *mig)
542743
 {
542743
-    spice_migrate *mig = data;
542743
     SpiceChannelPrivate  *c = SPICE_CHANNEL(mig->dst_channel)->priv;
542743
 
542743
     g_return_val_if_fail(c->channel_type == SPICE_CHANNEL_MAIN, FALSE);
542743
@@ -2348,9 +2389,8 @@ static gboolean main_migrate_handshake_done(gpointer data)
542743
 }
542743
 
542743
 /* main context */
542743
-static gboolean migrate_connect(gpointer data)
542743
+static gboolean migrate_connect(spice_migrate *mig)
542743
 {
542743
-    spice_migrate *mig = data;
542743
     SpiceChannelPrivate  *c;
542743
     int port, sport;
542743
     const char *host;
542743
@@ -2393,8 +2433,8 @@ static gboolean migrate_connect(gpointer data)
542743
     g_object_set(mig->session, "host", host, NULL);
542743
     spice_session_set_port(mig->session, port, FALSE);
542743
     spice_session_set_port(mig->session, sport, TRUE);
542743
-    g_signal_connect(mig->session, "channel-new",
542743
-                     G_CALLBACK(migrate_channel_new_cb), mig);
542743
+    spice_migrate_signal_connect(mig->session, "channel-new",
542743
+                                 G_CALLBACK(migrate_channel_new_cb), mig);
542743
 
542743
     g_signal_emit(mig->src_channel, signals[SPICE_MIGRATION_STARTED], 0,
542743
                   mig->session);
542743
@@ -2414,50 +2454,56 @@ static void main_migrate_connect(SpiceChannel *channel,
542743
 {
542743
     SpiceMainChannelPrivate *main_priv = SPICE_MAIN_CHANNEL(channel)->priv;
542743
     int reply_type = SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR;
542743
-    spice_migrate mig = { 0, };
542743
+    spice_migrate *mig;
542743
     SpiceMsgOut *out;
542743
     SpiceSession *session;
542743
 
542743
-    mig.src_channel = channel;
542743
-    mig.info = dst_info;
542743
-    mig.from = coroutine_self();
542743
-    mig.do_seamless = do_seamless;
542743
-    mig.src_mig_version = src_mig_version;
542743
+    mig = spice_new0(spice_migrate, 1);
542743
+    mig->ref_count = 1;
542743
+    mig->src_channel = channel;
542743
+    mig->info = dst_info;
542743
+    mig->from = coroutine_self();
542743
+    mig->do_seamless = do_seamless;
542743
+    mig->src_mig_version = src_mig_version;
542743
 
542743
     CHANNEL_DEBUG(channel, "migrate connect");
542743
     session = spice_channel_get_session(channel);
542743
-    mig.session = spice_session_new_from_session(session);
542743
-    if (mig.session == NULL)
542743
+    mig->session = spice_session_new_from_session(session);
542743
+    if (mig->session == NULL) {
542743
         goto end;
542743
-    if (!spice_session_set_migration_session(session, mig.session))
542743
+    }
542743
+    if (!spice_session_set_migration_session(session, mig->session)) {
542743
         goto end;
542743
+    }
542743
 
542743
-    main_priv->migrate_data = &mig;
542743
+    spice_migrate_unref(main_priv->migrate_data);
542743
+    main_priv->migrate_data = spice_migrate_ref(mig);
542743
 
542743
     /* no need to track idle, call is sync for this coroutine */
542743
-    g_idle_add(migrate_connect, &mig;;
542743
+    spice_migrate_idle_add(migrate_connect, mig);
542743
 
542743
     /* switch to main loop and wait for connections */
542743
     coroutine_yield(NULL);
542743
 
542743
-    if (mig.nchannels != 0) {
542743
+    if (mig->nchannels != 0) {
542743
         CHANNEL_DEBUG(channel, "migrate failed: some channels failed to connect");
542743
         spice_session_abort_migration(session);
542743
     } else {
542743
-        if (mig.do_seamless) {
542743
+        if (mig->do_seamless) {
542743
             SPICE_DEBUG("migration (seamless): connections all ok");
542743
             reply_type = SPICE_MSGC_MAIN_MIGRATE_CONNECTED_SEAMLESS;
542743
         } else {
542743
             SPICE_DEBUG("migration (semi-seamless): connections all ok");
542743
             reply_type = SPICE_MSGC_MAIN_MIGRATE_CONNECTED;
542743
         }
542743
-        spice_session_start_migrating(session, mig.do_seamless);
542743
+        spice_session_start_migrating(session, mig->do_seamless);
542743
     }
542743
 
542743
 end:
542743
     CHANNEL_DEBUG(channel, "migrate connect reply %d", reply_type);
542743
     out = spice_msg_out_new(channel, reply_type);
542743
     spice_msg_out_send(out);
542743
+    spice_migrate_unref(mig);
542743
 }
542743
 
542743
 /* coroutine context */
542743
@@ -2489,7 +2535,7 @@ static void main_handle_migrate_dst_seamless_ack(SpiceChannel *channel, SpiceMsg
542743
 
542743
     g_return_if_fail(c->state == SPICE_CHANNEL_STATE_MIGRATION_HANDSHAKE);
542743
     main_priv->migrate_data->do_seamless = true;
542743
-    g_idle_add(main_migrate_handshake_done, main_priv->migrate_data);
542743
+    spice_migrate_idle_add(main_migrate_handshake_done, main_priv->migrate_data);
542743
 }
542743
 
542743
 static void main_handle_migrate_dst_seamless_nack(SpiceChannel *channel, SpiceMsgIn *in)
542743
@@ -2501,7 +2547,7 @@ static void main_handle_migrate_dst_seamless_nack(SpiceChannel *channel, SpiceMs
542743
 
542743
     g_return_if_fail(c->state == SPICE_CHANNEL_STATE_MIGRATION_HANDSHAKE);
542743
     main_priv->migrate_data->do_seamless = false;
542743
-    g_idle_add(main_migrate_handshake_done, main_priv->migrate_data);
542743
+    spice_migrate_idle_add(main_migrate_handshake_done, main_priv->migrate_data);
542743
 }
542743
 
542743
 /* main context */
542743
-- 
542743
2.28.0
542743