mirror of
				https://github.com/zeromq/libzmq.git
				synced 2025-11-04 04:10:00 +01:00 
			
		
		
		
	Merge pull request #2971 from ZMQers/fix-static-init
Problem: static initialization order fiasco
This commit is contained in:
		@@ -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)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ++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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user