GNOME Bugzilla – Bug 625584
Crashes application on unref with signal subscription
Last modified: 2010-08-24 08:54:24 UTC
I'm trying to receive a signal of "server gone" with GDBus. My client part is able to notice it, by "NameOwnerChanged" member, but if I close connection (unref proxy) in such situation, then application crashes later, with a backtrace (see below). I'm listening for a signal by g_dbus_connection_signal_subscribe which seems to be the cause.
+ Trace 223039
Thread 1 (Thread 0xb7fd5760 (LWP 20691))
Aha, this happens because the finalizer runs while we're holding a lock: #3 0x0103367f in g_assertion_message (domain=0x7196a3 "GLib-GIO", file=0x7199b9 "gdbusconnection.c", line=1180, func=0x71bd80 "g_dbus_connection_send_message_unlocked", message=0x7199e4 "CONNECTION_ENSURE_LOCK: GDBusConnection object lock is not locked") at gtestutils.c:1330 #8 0x006c4b08 in g_dbus_connection_finalize (object=0x8064858) at gdbusconnection.c:440 #9 0x007f1ba9 in g_object_unref (_object=0x8064858) at gobject.c:2578 #10 0x006c990f in signal_instance_free (signal_instance=0xb7406500) at gdbusconnection.c:3101 The way to solve this is probably to take an extra reference while taking the lock....
Milan, if you have a glib checkout handy, try adding add g_object_ref/g_object_unref invocations to the CONNECTION_LOCK/CONNETION_UNLOCK macros in gdbusconnection.c and then see if that fixes it - I think it will.
Hrm, the above was with glib 2.25.11. I tried to add ref/unref and also updated to 2.25.12 and it still crashes, but the backtrace is slightly different:
+ Trace 223044
Actually it happens because the object is not locked and the finalizer calls code that expects the object to be locked. The following test case reproduces the bug diff --git a/gio/tests/gdbus-connection.c b/gio/tests/gdbus-connection.c index 4b25aa3..1de88bd 100644 --- a/gio/tests/gdbus-connection.c +++ b/gio/tests/gdbus-connection.c @@ -37,6 +37,24 @@ static GMainLoop *loop = NULL; /* ---------------------------------------------------------------------------------------------------- */ static void +on_name_owner_changed (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ +} + +static void +a_destroy_notify_that_sets_a_gboolean_to_true (gpointer user_data) +{ + gboolean *val = user_data; + *val = TRUE; +} + +static void test_connection_life_cycle (void) { gboolean ret; @@ -100,6 +118,32 @@ test_connection_life_cycle (void) g_object_unref (c2); /* + * Check that the finalization code works + * + * (and that the GDestroyNotify for filters and objects and signal + * registrations are run as expected) + */ + gboolean on_name_owner_changed_freed_called; + on_name_owner_changed_freed_called = FALSE; + error = NULL; + c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &error); + g_assert_no_error (error); + g_assert (c2 != NULL); + g_dbus_connection_signal_subscribe (c2, + "org.freedesktop.DBus", /* bus name */ + "org.freedesktop.DBus", /* interface */ + "NameOwnerChanged", /* member */ + "/org/freesktop/DBus", /* path */ + NULL, /* arg0 */ + G_DBUS_SIGNAL_FLAGS_NONE, + on_name_owner_changed, + &on_name_owner_changed_freed_called, + a_destroy_notify_that_sets_a_gboolean_to_true); + g_assert (!on_name_owner_changed_freed_called); + g_object_unref (c2); + g_assert (on_name_owner_changed_freed_called); + + /* * Check for correct behavior when the bus goes away * */
Fixed here http://git.gnome.org/browse/glib/commit/?id=d2d97a214d1d9e96f09955212e669c3c9447ff73 including a test case to ensure that this (and similar bugs) don't happen again.
Milan, please check if this fix works - if not, please REOPEN, thanks :-)
Seems to work fine, thanks.