mirror of
https://github.com/zeromq/libzmq.git
synced 2025-11-03 11:26:22 +01:00
Merge pull request #2971 from ZMQers/fix-static-init
Problem: static initialization order fiasco
This commit is contained in:
@@ -79,41 +79,76 @@ 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 (random_refcount == 0) {
|
#if ZMQ_HAVE_THREADSAFE_STATIC_LOCAL_INIT
|
||||||
int rc = sodium_init ();
|
static int random_refcount = 0;
|
||||||
zmq_assert (rc != -1);
|
static zmq::mutex_t random_sync;
|
||||||
}
|
|
||||||
|
|
||||||
++random_refcount;
|
|
||||||
#else
|
|
||||||
LIBZMQ_UNUSED (random_refcount);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (init) {
|
||||||
|
zmq::scoped_lock_t locker (random_sync);
|
||||||
|
|
||||||
|
if (random_refcount == 0) {
|
||||||
|
int rc = sodium_init ();
|
||||||
|
zmq_assert (rc != -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
++random_refcount;
|
||||||
|
} else {
|
||||||
|
zmq::scoped_lock_t locker (random_sync);
|
||||||
|
--random_refcount;
|
||||||
|
|
||||||
|
if (random_refcount == 0) {
|
||||||
|
randombytes_close ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void zmq::random_open (void)
|
||||||
|
{
|
||||||
|
manage_random (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void zmq::random_close (void)
|
void zmq::random_close (void)
|
||||||
{
|
{
|
||||||
#if defined(ZMQ_USE_LIBSODIUM) \
|
manage_random (false);
|
||||||
|| (defined(ZMQ_USE_TWEETNACL) && !defined(ZMQ_HAVE_WINDOWS) \
|
|
||||||
&& !defined(ZMQ_HAVE_GETRANDOM))
|
|
||||||
scoped_lock_t locker (random_sync);
|
|
||||||
--random_refcount;
|
|
||||||
|
|
||||||
if (random_refcount == 0) {
|
|
||||||
randombytes_close ();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user