From dba687f01cfe5aad36c3df1b830b1e1d6ab4592d Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Tue, 15 May 2012 12:20:19 -0400 Subject: [PATCH] soup-message-io: keep cancellable alive for duration of io_run_until io_run() passes io->cancellable to io_run_until(), but io may be destroyed (and cancellable unreffed) before io_run_until() returns, causing it to eventually call g_cancellable_is_cancelled() on garbage. Fix by reffing it around the io_run_until() call (though really this is just another example of "SoupMessageIOData needs to be refcounted".) Tweak misc-test to test this case. Fixes crasher in rygel test case. Based on a patch from Ray Strode. https://bugzilla.gnome.org/show_bug.cgi?id=676038 --- libsoup/soup-message-io.c | 6 +++++- tests/misc-test.c | 18 +++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c index 455265e..7a554df 100644 --- a/libsoup/soup-message-io.c +++ b/libsoup/soup-message-io.c @@ -886,6 +886,7 @@ io_run (SoupMessage *msg, gpointer user_data) SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg); SoupMessageIOData *io = priv->io_data; GError *error = NULL; + GCancellable *cancellable; if (io->io_source) { g_source_destroy (io->io_source); @@ -894,11 +895,12 @@ io_run (SoupMessage *msg, gpointer user_data) } g_object_ref (msg); + cancellable = io->cancellable ? g_object_ref (io->cancellable) : NULL; if (io_run_until (msg, SOUP_MESSAGE_IO_STATE_DONE, SOUP_MESSAGE_IO_STATE_DONE, - io->cancellable, &error)) { + cancellable, &error)) { soup_message_io_finished (msg); } else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { g_clear_error (&error); @@ -909,6 +911,8 @@ io_run (SoupMessage *msg, gpointer user_data) } g_object_unref (msg); + g_clear_object (&cancellable); + return FALSE; } diff --git a/tests/misc-test.c b/tests/misc-test.c index 39d63d3..a2b9937 100644 --- a/tests/misc-test.c +++ b/tests/misc-test.c @@ -857,11 +857,20 @@ cancel_message_thread (gpointer msg) } static void +set_done (SoupSession *session, SoupMessage *msg, gpointer user_data) +{ + gboolean *done = user_data; + + *done = TRUE; +} + +static void do_cancel_while_reading_test_for_session (SoupSession *session) { SoupMessage *msg; GThread *thread = NULL; SoupURI *uri; + gboolean done = FALSE; uri = soup_uri_new_with_base (base_uri, "/slow"); msg = soup_message_new_from_uri ("GET", uri); @@ -875,7 +884,14 @@ do_cancel_while_reading_test_for_session (SoupSession *session) else thread = g_thread_new ("cancel_message_thread", cancel_message_thread, msg); - soup_session_send_message (session, msg); + /* We intentionally don't use soup_session_send_message() here, + * because it holds an extra ref on the SoupMessageQueueItem + * relative to soup_session_queue_message(). + */ + g_object_ref (msg); + soup_session_queue_message (session, msg, set_done, &done); + while (!done) + g_main_context_iteration (NULL, TRUE); if (msg->status_code != SOUP_STATUS_CANCELLED) { debug_printf (1, " FAILED: %d %s (expected Cancelled)\n", -- 2.7.4