I've recently been investigating a crash which was traced to
interactions between libdbus, glib-networking and pacrunner's libproxy
shim, and thought I should open a bug or something. I can't find a bug
tracker for pacrunner, so, mailing list it is...

Background
----------

Based on cursory inspection of its source code, "the real libproxy"
appears to be designed to be thread-safe. The plugin in glib-networking
that uses libproxy as a backend for GIO proxy resolution calls into
libproxy from threads: in particular, if you are resolving the proxy for
two URLs, glib-networking can be blocking in
px_proxy_factory_get_proxies() from more than one thread at the same
time. (This is not theoretical; I've seen it happen in gdb.)

pacrunner's shim implementation of libproxy uses libdbus, wrapping a
private DBusConnection. However, libdbus has a long-standing design
flaw, rooted in its efforts to be widely portable: it is not thread-safe
unless an application explicitly tells it to be thread-safe (at which
point it initializes locks for global data structures, etc.). In an
ideal world, yes this should be fixed (and I've developed patches that I
think do that), but the changes are not trivial, and there are several
years' worth of libdbus versions that are not thread-safe by default.

The way an application tells libdbus to be thread-safe is:

    if (!dbus_threads_init_default ())
      fatal ("out of memory"); /* or some better error-handling */

However, dbus_threads_init_default() is not itself thread-safe: if
you're pathologically unlucky, two threads calling
dbus_threads_init_default() simultaneously could result in crashes! Its
documented correct usage is basically "call it before you start your
second thread", which is not something that a library like libproxy can
do without help from its host application. Again, this is undeniably a
design flaw, but fixing it is not trivial.

(The pacrunner *daemon* does use dbus_threads_init_default() correctly,
i.e. from main() before it does anything significant.)

Solutions
---------

The ideal solution for the future is fixing those design flaws in
libdbus 1.7, for which I have patches up for review at
<https://bugs.freedesktop.org/show_bug.cgi?id=54972> (reviews from
multi-threading experts would be extremely welcome); but that can't
retroactively fix older versions, so something else is still needed.

One possible solution is to use a better library, written with the
benefit of hindsight (not replicating libdbus' mistakes). GIO's GDBus is
LGPL, C, thread-safe by default since 2.32, and appears to be
well-designed for multi-threaded situations, although it does add a
library dependency (libgio-2.0).

Another possible solution is to document pacrunner's libproxy as an
imperfect emulation of "the real libproxy" in that it is not
thread-safe, and warn its users to audit their applications to ensure
that they avoid using libproxy from non-main threads unless the host
application is known to have called dbus_threads_init_default() on
startup. In the case of glib-networking, which does use threads and
cannot generally assume that that dbus_threads_init_default() has been
called, that would probably mean not compiling its libproxy module
against the shim libproxy, and instead using a new "pacrunner" module
that makes the same D-Bus calls using GDBus.

Another possibility is for the shim libproxy to call
dbus_threads_init_default() during px_proxy_factory_new(), in the hope
that it is not racing with another thread - this is itself neither safe
nor correct, but it seems likely to be less bad, since two threads
calling px_proxy_factory_new() simultaneously seems less likely than two
threads calling px_proxy_factory_get_proxies() simultaneously. If you do
this, please consult the libdbus source code to confirm what can go
wrong and how likely it is.

(If my first few patches from
<https://bugs.freedesktop.org/show_bug.cgi?id=54972> are reviewed and
merged, in subsequent releases calling dbus_threads_init_default() from
arbitrary threads at arbitrary times will become a safe, correct and
documented thing to do; if the whole patch series is merged, it will
also become unnecessary.)

Regards,
    S

_______________________________________________
connman mailing list
connman@connman.net
http://lists.connman.net/listinfo/connman

Reply via email to