[gupnp] ServiceProxy: Fix double-free on ProxyAction



commit c83073359f09dc987e5265171d629eb5f261e4e6
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
    
    Fixes #60

 libgupnp/gupnp-service-proxy.c |  2 +-
 tests/test-bugs.c              | 69 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+), 1 deletion(-)
---
diff --git a/libgupnp/gupnp-service-proxy.c b/libgupnp/gupnp-service-proxy.c
index 0cca2a8..7cf6c6d 100644
--- a/libgupnp/gupnp-service-proxy.c
+++ b/libgupnp/gupnp-service-proxy.c
@@ -798,7 +798,7 @@ action_task_got_response (GObject *source,
 
                 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 cb78e63..40aa782 100644
--- a/tests/test-bugs.c
+++ b/tests/test-bugs.c
@@ -926,6 +926,74 @@ 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_test_get_path ());
+        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, g_test_get_path());
+        gupnp_service_proxy_action_unref (action);
+        g_object_unref (data.proxy);
+        g_object_unref (rd);
+        g_object_unref (cp);
+        g_object_unref (context);
+
+        // Make sure the source teardown handlers get run so we don't confuse valgrind
+        g_timeout_add (500, (GSourceFunc) delayed_loop_quitter, data.loop);
+        g_main_loop_run (data.loop);
+
+        g_main_loop_unref (data.loop);
+}
+
 int
 main (int argc, char *argv[]) {
     g_test_init (&argc, &argv, NULL);
@@ -938,6 +1006,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", test_ggo_60_no_crash);
 
     return g_test_run ();
 }


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