Bug 24412 - Dbus-glib doesn't partake in dbus watch reference counting causing crash in the error unwind
Summary: Dbus-glib doesn't partake in dbus watch reference counting causing crash in t...
Status: RESOLVED DUPLICATE of bug 15578
Alias: None
Product: dbus
Classification: Unclassified
Component: GLib (show other bugs)
Version: 1.2.x
Hardware: Other All
: medium normal
Assignee: Rob Taylor
QA Contact: John (J5) Palmieri
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-10-08 17:10 UTC by James Westby
Modified: 2011-04-14 04:36 UTC (History)
0 users

See Also:
i915 platform:
i915 features:


Attachments

Description James Westby 2009-10-08 17:10:37 UTC
Hi,

  https://bugs.launchpad.net/ubuntu/+source/dbus-glib/+bug/441190

is what triggered me to look at this. It has the following stacktrace

#0  io_handler_watch_freed (data=0x0) at dbus-gmain.c:198
No locals.
#1  0x00007fde8af8565b in dbus_watch_set_data (watch=0x24b8090, data=0x0, 
    free_data_function=0) at dbus-watch.c:602
No locals.
#2  0x00007fde8af85881 in _dbus_watch_unref (watch=0x0) at dbus-watch.c:131
No locals.
#3  0x00007fde8af84e89 in free_watches (transport=0x2305d70)
    at dbus-transport-socket.c:83
No locals.
#4  0x00007fde8af84ee9 in socket_disconnect (transport=0x0)
    at dbus-transport-socket.c:928
No locals.
#5  0x00007fde8af82ea7 in _dbus_transport_disconnect (transport=0x2305d70)
    at dbus-transport.c:494
No locals.
#6  0x00007fde8af838a3 in _dbus_transport_queue_messages (transport=0x2305d70)
    at dbus-transport.c:1137
	status = <value optimized out>



It looks to me as though dbus-glib isn't taking part in dbus' reference counting:

In dbus, as things are being torn down:

  _dbus_watch_unref(...
  .
  .
  .
    if (watch->refcount == 0)
      {
        dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */

which frees the data.

in dbus-glib

  connection_setup_add_watch(...
  .
  .
  .
    channel = g_io_channel_unix_new (dbus_watch_get_unix_fd (watch));

    handler->source = g_io_create_watch (channel, condition);
    g_source_set_callback (handler->source, (GSourceFunc) io_handler_dispatch, handler,
                           io_handler_source_finalized);

so io_handler_source_finalized will be called as the watch is torn down

  io_handler_source_finalized (gpointer data)
  {
    IOHandler *handler;

    handler = data;

    if (handler->watch)
      dbus_watch_set_data (handler->watch, NULL, NULL);

which frees the data regardless.

This isn't a race, the way io_handler_watch_freed is coded, it will
crash regardless of the ordering here.

I think this isn't an issue for every use, as we are in an exception case in
dbus itself:

    if (_dbus_message_loader_get_is_corrupted (transport->loader))
    {
      _dbus_verbose ("Corrupted message stream, disconnecting\n");
      _dbus_transport_disconnect (transport);

As for a fix, I'm not sure, should dbus-glib take part in the refcounting,
or just not bother freeing the data and rely on dbus to do it?

Thanks,

James
Comment 1 Simon McVittie 2011-04-14 04:08:50 UTC
(In reply to comment #0)
> It looks to me as though dbus-glib isn't taking part in dbus' reference
> counting:

Nothing outside libdbus can take part in DBusWatch refcounting, because _dbus_watch_unref is private to libdbus.

>     if (watch->refcount == 0)
>       {
>         dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */
...
>     if (handler->watch)
>       dbus_watch_set_data (handler->watch, NULL, NULL);

It should be fine that this can be called twice: it's setting the watch's user-data to NULL, but simultaneously setting the user-data free-function to NULL, so the old free-function will only be called on the old user-data, and only once.

Also, io_handler_watch_freed sets handler->watch to NULL, and io_handler_source_finalized only calls dbus_watch_set_data if the watch has not been freed; so it can only be called once anyway, as far as I can see.

I don't think this crash is necessarily dbus-glib's fault. A regression test would probably be useful: perhaps it could connect a peer-to-peer DBus(G)Connection to a listening Unix socket, and have the listening socket authenticate correctly but then send meaningless data instead of a valid message.
Comment 2 Simon McVittie 2011-04-14 04:36:52 UTC
I think this is probably the same thing as Bug #15578 in libdbus; nobody has reproduced that one either.

*** This bug has been marked as a duplicate of bug 15578 ***


Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.