Page MenuHome GnuPG

Cannot be made thread-safe when used by a library
Closed, ResolvedPublic

Description

This was originally reported as a Firefox crash when printing through the CUPS
library.

Here is the description by Caolan McNamara:
a) firefox dlopens cups
b) cups calls...

gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
gnutls_global_init();

Due to rhb#544619# the idea was to ensure that libgcrypt gets locked to avoid
multiple threads using neon (that itself may use libgcrypt) from trampling over
their shared libgcrypt. Hence the gcry_control added to cups (along the lines
suggested at
http://www.gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html) to
make sure that if cups + neon is used in an app and cups is used first then all
works well if multiple threads use neon later one.

c) firefox dlcloses cups
d) firefox dlopens cups
e) cups calls...

gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
gnutls_global_init();

In libgcrypt's src/global.c

case GCRYCTL_SET_THREAD_CBS:
  err = ath_install (va_arg (arg_ptr, void *), any_init_done);

any_init_done is still true from the *last* init, and ath_install is
effectively a no-op if any_init_done is true. So the new pthread stuff isn't
installed, and libgcrypt still points to the old info which was destroyed at
the first dlclose of cups.

Its all a bit unfortunate. If e.g. libgcrypt had way to query the
GCRYCTL_SET_THREAD_CBS info then libs using it could either

a) store a copy of the old info if it existed, install their own on their init
and restore the old one on their deinit.
b) only install one if one didn't exist (possible now) and *remove* their one
on deinit (not possible now)

Its not really practical in general of course for the *app* to call
gcry_control (GCRYCTL_SET_THREAD_CBS...) because how is it to know that
libgcrypt is being used by any of its libraries. Though that would solve the
problem in this case seeing as any other GCRYCTL_SET_THREAD_CBS would be
ignored, and the one installed during dlopen of cups wouldn't apply.

So long and short of it is that it's currently hopeless to use
GCRYCTL_SET_THREAD_CBS in a library because that library can be dlclosed,
destroying the locking functions that were installed into libgcrypt.

See also:
https://bugzilla.redhat.com/show_bug.cgi?id=553834
and
https://bugzilla.redhat.com/show_bug.cgi?id=569803

Details

Version
gnupg 2.0.14

Event Timeline

t8m added projects: Feature Request, libgcrypt.
t8m added a subscriber: t8m.
werner changed Version from 2.0.14 to gnupg 2.0.14.Feb 21 2011, 3:02 PM
werner added a subscriber: werner.

Libraries are a part of the application. Hiding all details of a
library is simply not possible. You suggestion does not work either;
because switching the thread system is not possible: Either you are
using thread system A or thread system B; A can't switch to B, because
it does not know about B's internals.

In any case, we have discussed this internally and our conclusion is
to give up the customizable thread support. In the future we will
assume one thread system for a certain platform and there won't be a
way to use a different. To implement this, we need to write an Pth
emulation library, because GnuPG uses Pth and Pth and Pthreads can't
be used together. Note, we did such an emulation for Windows already
(where there is no Pth port) and that one works really well for many
years.

We will address this in 1.6. At least for ELF systems supporting the weak
pragma and for W32.

werner claimed this task.
werner removed a project: Stalled.
werner added projects: Won't Fix, Too Old.

Libgcrypt 1.6 will be released this year.