After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 625584 - Crashes application on unref with signal subscription
Crashes application on unref with signal subscription
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: gdbus
2.25.x
Other Linux
: Normal critical
: ---
Assigned To: David Zeuthen (not reading bugmail)
gtkdev
Depends on:
Blocks: 625514
 
 
Reported: 2010-07-29 13:50 UTC by Milan Crha
Modified: 2010-08-24 08:54 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Milan Crha 2010-07-29 13:50:58 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.

Thread 1 (Thread 0xb7fd5760 (LWP 20691))

  • #0 __kernel_vsyscall
  • #1 raise
    at ../nptl/sysdeps/unix/sysv/linux/raise.c line 64
  • #2 abort
    at abort.c line 92
  • #3 g_assertion_message
    at gtestutils.c line 1330
  • #4 g_dbus_connection_send_message_unlocked
    at gdbusconnection.c line 1180
  • #5 remove_match_rule
    at gdbusconnection.c line 2754
  • #6 unsubscribe_id_internal
    at gdbusconnection.c line 2971
  • #7 purge_all_signal_subscriptions
    at gdbusconnection.c line 3255
  • #8 g_dbus_connection_finalize
    at gdbusconnection.c line 440
  • #9 g_object_unref
    at gobject.c line 2578
  • #10 signal_instance_free
    at gdbusconnection.c line 3101
  • #11 g_source_callback_unref
    at gmain.c line 1152
  • #12 g_source_destroy_internal
    at gmain.c line 931
  • #13 g_main_dispatch
    at gmain.c line 2144
  • #14 g_main_context_dispatch
    at gmain.c line 2672
  • #15 g_main_context_iterate
    at gmain.c line 2750
  • #16 g_main_loop_run
    at gmain.c line 2958
  • #17 main
    at test-changes.c line 68

Comment 1 David Zeuthen (not reading bugmail) 2010-07-29 14:00:16 UTC
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....
Comment 2 David Zeuthen (not reading bugmail) 2010-07-29 14:57:10 UTC
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.
Comment 3 Milan Crha 2010-07-29 19:03:39 UTC
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:

  • #1 raise
    at ../nptl/sysdeps/unix/sysv/linux/raise.c line 64
  • #2 abort
    at abort.c line 92
  • #3 g_assertion_message
    at gtestutils.c line 1358
  • #4 g_dbus_connection_send_message_unlocked
    at gdbusconnection.c line 1300
  • #5 remove_match_rule
    at gdbusconnection.c line 2883
  • #6 unsubscribe_id_internal
    at gdbusconnection.c line 3103
  • #7 purge_all_signal_subscriptions
    at gdbusconnection.c line 3387
  • #8 g_dbus_connection_finalize
    at gdbusconnection.c line 442
  • #9 g_object_unref
    at gobject.c line 2580
  • #10 signal_instance_free
    at gdbusconnection.c line 3233
  • #11 g_source_callback_unref
    at gmain.c line 1152
  • #12 g_source_destroy_internal
    at gmain.c line 931
  • #13 g_main_dispatch
    at gmain.c line 2144
  • #14 g_main_context_dispatch
    at gmain.c line 2672
  • #15 g_main_context_iterate
    at gmain.c line 2750
  • #16 g_main_loop_run
    at gmain.c line 2958
  • #17 main
    at test-changes.c line 68

Comment 4 David Zeuthen (not reading bugmail) 2010-07-30 19:19:46 UTC
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
    *
    */
Comment 5 David Zeuthen (not reading bugmail) 2010-07-30 20:07:10 UTC
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.
Comment 6 David Zeuthen (not reading bugmail) 2010-07-30 20:10:31 UTC
Milan, please check if this fix works - if not, please REOPEN, thanks :-)
Comment 7 Milan Crha 2010-08-24 08:54:24 UTC
Seems to work fine, thanks.