[gupnp/gupnp-1.4] ServiceProxy: Fix double-free on ProxyAction



commit 774d996767b2085966b3eb98fb6e07dc178d37e3
Author: Jens Georg <mail jensge org>
Date:   Sat Jan 8 09:21:10 2022 +0100

    ServiceProxy: Fix double-free on ProxyAction
    
    If call_finish() is not called, do not unref the action since it is
    bound to the task's lifetime anyway

 libgupnp/gupnp-service-proxy.c |  2 +-
 tests/test-bugs.c              | 82 +++++++++++++++++++++++++++++++++++++++---
 2 files changed, 78 insertions(+), 6 deletions(-)
---
diff --git a/libgupnp/gupnp-service-proxy.c b/libgupnp/gupnp-service-proxy.c
index 5e78ebf..bcf9439 100644
--- a/libgupnp/gupnp-service-proxy.c
+++ b/libgupnp/gupnp-service-proxy.c
@@ -775,7 +775,7 @@ action_task_got_response (SoupSession *session,
 
                 g_task_return_pointer (task,
                                        g_task_get_task_data (task),
-                                       (GDestroyNotify) gupnp_service_proxy_action_unref);
+                                       NULL);
 
                 g_object_unref (task);
 
diff --git a/tests/test-bugs.c b/tests/test-bugs.c
index df1a29e..24cf1fc 100644
--- a/tests/test-bugs.c
+++ b/tests/test-bugs.c
@@ -173,11 +173,19 @@ test_on_timeout (G_GNUC_UNUSED gpointer user_data)
 static void
 test_run_loop (GMainLoop *loop)
 {
-    guint timeout_id = 0;
-
-    timeout_id = g_timeout_add_seconds (2, test_on_timeout, NULL);
-    g_main_loop_run (loop);
-    g_source_remove (timeout_id);
+        guint timeout_id = 0;
+        int timeout = 2;
+
+        const char *timeout_str = g_getenv ("GUPNP_TEST_TIMEOUT");
+        if (timeout_str != NULL) {
+                long t = atol (timeout_str);
+                if (t != 0)
+                        timeout = t;
+        }
+
+        timeout_id = g_timeout_add_seconds (timeout, test_on_timeout, NULL);
+        g_main_loop_run (loop);
+        g_source_remove (timeout_id);
 }
 
 /* Test if a call on a service proxy keeps argument order */
@@ -837,6 +845,69 @@ test_ggo_63 ()
         g_main_loop_unref (d.loop);
 }
 
+void
+test_ggo_60_call_ready (GObject *source, GAsyncResult *res, gpointer user_data)
+{
+        g_main_loop_quit ((GMainLoop *) user_data);
+}
+
+void
+test_ggo_60_no_crash ()
+{
+        // Test that there is no crash if not calling call_finish() on call_async()
+        GUPnPContext *context = NULL;
+        GError *error = NULL;
+        GUPnPControlPoint *cp = NULL;
+        GUPnPRootDevice *rd;
+        TestServiceProxyData data = { .proxy = NULL,
+                                      .loop = g_main_loop_new (NULL, FALSE) };
+
+        context = create_context (0, &error);
+        g_assert_no_error (error);
+        g_assert (context != NULL);
+
+        cp = gupnp_control_point_new (
+                context,
+                "urn:test-gupnp-org:service:TestService:1");
+
+        gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE);
+
+        g_signal_connect (G_OBJECT (cp),
+                          "service-proxy-available",
+                          G_CALLBACK (test_on_sp_available),
+                          &data);
+
+
+        rd = gupnp_root_device_new (context,
+                                    "TestDevice.xml",
+                                    DATA_PATH,
+                                    &error);
+        g_assert_no_error (error);
+        g_assert (rd != NULL);
+        gupnp_root_device_set_available (rd, TRUE);
+        test_run_loop (data.loop);
+        g_assert (data.proxy != NULL);
+
+        // We just use the default of "Action not implemented" response, since
+        // it does not matter for the actual test
+
+        GUPnPServiceProxyAction *action =
+                gupnp_service_proxy_action_new ("Ping", NULL);
+        gupnp_service_proxy_call_action_async (data.proxy,
+                                               action,
+                                               NULL,
+                                               test_ggo_60_call_ready,
+                                               data.loop);
+
+        test_run_loop (data.loop);
+        gupnp_service_proxy_action_unref (action);
+        g_object_unref (data.proxy);
+        g_object_unref (rd);
+        g_object_unref (cp);
+        g_object_unref (context);
+        g_main_loop_unref (data.loop);
+}
+
 int
 main (int argc, char *argv[]) {
     g_test_init (&argc, &argv, NULL);
@@ -849,6 +920,7 @@ main (int argc, char *argv[]) {
     g_test_add_func ("/bugs/ggo/58", test_ggo_58);
     g_test_add_func ("/bugs/ggo/42", test_ggo_42);
     g_test_add_func ("/bugs/ggo/63", test_ggo_63);
+    g_test_add_func ("/bugs/ggo/60/no-crash", test_ggo_60_no_crash);
 
     return g_test_run ();
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]