Unverified Commit 10d2b288 authored by Luca Boccassi's avatar Luca Boccassi Committed by GitHub

Merge pull request #2971 from ZMQers/fix-static-init

Problem: static initialization order fiasco
parents 494c2a71 8cdfc8b9
...@@ -79,19 +79,52 @@ uint32_t zmq::generate_random () ...@@ -79,19 +79,52 @@ uint32_t zmq::generate_random ()
// The context class cannot be used with static variables as the curve // The context class cannot be used with static variables as the curve
// utility APIs like zmq_curve_keypair also call into the crypto // utility APIs like zmq_curve_keypair also call into the crypto
// library. // library.
// The safest solution for all use cases therefore is to have a global, // The safest solution for all use cases therefore is to have a
// static lock to serialize calls into an initialiser and a finaliser, // static lock to serialize calls into an initialiser and a finaliser,
// using refcounts to make sure that a thread does not close the library // using refcounts to make sure that a thread does not close the library
// while another is still using it. // while another is still using it. To avoid the static initialization
// order fiasco, this is done using function-local statics, if the
// compiler implementation supports thread-safe initialization of those.
// Otherwise, we fall back to global statics.
// TODO if there is some other user of libsodium besides libzmq, this must
// be synchronized by the application. This should probably also be
// configurable via config.h
// TODO this should probably be done via config.h
#if __cplusplus >= 201103L \
|| (defined(__cpp_threadsafe_static_init) \
&& __cpp_threadsafe_static_init >= 200806) \
|| (defined(_MSC_VER) && _MSC_VER >= 1900)
#define ZMQ_HAVE_THREADSAFE_STATIC_LOCAL_INIT 1
// TODO this might probably also be set if a sufficiently recent gcc is used
// without -fno-threadsafe-statics, but this cannot be determined at
// compile-time, so it must be set via config.h
#else
#define ZMQ_HAVE_THREADSAFE_STATIC_LOCAL_INIT 0
#endif
#if !ZMQ_HAVE_THREADSAFE_STATIC_LOCAL_INIT \
&& (defined(ZMQ_USE_LIBSODIUM) \
|| (defined(ZMQ_USE_TWEETNACL) && !defined(ZMQ_HAVE_WINDOWS) \
&& !defined(ZMQ_HAVE_GETRANDOM)))
static unsigned int random_refcount = 0; static unsigned int random_refcount = 0;
static zmq::mutex_t random_sync; static zmq::mutex_t random_sync;
#endif
void zmq::random_open (void) static void manage_random (bool init)
{ {
#if defined(ZMQ_USE_LIBSODIUM) \ #if defined(ZMQ_USE_LIBSODIUM) \
|| (defined(ZMQ_USE_TWEETNACL) && !defined(ZMQ_HAVE_WINDOWS) \ || (defined(ZMQ_USE_TWEETNACL) && !defined(ZMQ_HAVE_WINDOWS) \
&& !defined(ZMQ_HAVE_GETRANDOM)) && !defined(ZMQ_HAVE_GETRANDOM))
scoped_lock_t locker (random_sync);
#if ZMQ_HAVE_THREADSAFE_STATIC_LOCAL_INIT
static int random_refcount = 0;
static zmq::mutex_t random_sync;
#endif
if (init) {
zmq::scoped_lock_t locker (random_sync);
if (random_refcount == 0) { if (random_refcount == 0) {
int rc = sodium_init (); int rc = sodium_init ();
...@@ -99,21 +132,23 @@ void zmq::random_open (void) ...@@ -99,21 +132,23 @@ void zmq::random_open (void)
} }
++random_refcount; ++random_refcount;
#else } else {
LIBZMQ_UNUSED (random_refcount); zmq::scoped_lock_t locker (random_sync);
#endif
}
void zmq::random_close (void)
{
#if defined(ZMQ_USE_LIBSODIUM) \
|| (defined(ZMQ_USE_TWEETNACL) && !defined(ZMQ_HAVE_WINDOWS) \
&& !defined(ZMQ_HAVE_GETRANDOM))
scoped_lock_t locker (random_sync);
--random_refcount; --random_refcount;
if (random_refcount == 0) { if (random_refcount == 0) {
randombytes_close (); randombytes_close ();
} }
}
#endif #endif
} }
void zmq::random_open (void)
{
manage_random (true);
}
void zmq::random_close (void)
{
manage_random (false);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment