@@ -484,40 +484,53 @@ print_mem_leaks(VALUE self)
484484/**
485485 * Stores locks needed for OpenSSL thread safety
486486 */
487- static rb_nativethread_lock_t * ossl_locks ;
487+ struct CRYPTO_dynlock_value {
488+ rb_nativethread_lock_t lock ;
489+ rb_nativethread_id_t owner ;
490+ size_t count ;
491+ };
488492
489493static void
490- ossl_lock_unlock ( int mode , rb_nativethread_lock_t * lock )
494+ ossl_lock_init ( struct CRYPTO_dynlock_value * l )
491495{
492- if (mode & CRYPTO_LOCK ) {
493- rb_nativethread_lock_lock (lock );
494- } else {
495- rb_nativethread_lock_unlock (lock );
496- }
496+ rb_nativethread_lock_initialize (& l -> lock );
497+ l -> count = 0 ;
497498}
498499
499500static void
500- ossl_lock_callback (int mode , int type , const char * file , int line )
501+ ossl_lock_unlock (int mode , struct CRYPTO_dynlock_value * l )
501502{
502- ossl_lock_unlock (mode , & ossl_locks [type ]);
503+ if (mode & CRYPTO_LOCK ) {
504+ /* TODO: rb_nativethread_id_t is not necessarily compared with ==. */
505+ rb_nativethread_id_t tid = rb_nativethread_self ();
506+ if (l -> count && l -> owner == tid ) {
507+ l -> count ++ ;
508+ return ;
509+ }
510+ rb_nativethread_lock_lock (& l -> lock );
511+ l -> owner = tid ;
512+ l -> count = 1 ;
513+ } else {
514+ if (!-- l -> count )
515+ rb_nativethread_lock_unlock (& l -> lock );
516+ }
503517}
504518
505- struct CRYPTO_dynlock_value {
506- rb_nativethread_lock_t lock ;
507- };
508-
509519static struct CRYPTO_dynlock_value *
510520ossl_dyn_create_callback (const char * file , int line )
511521{
512- struct CRYPTO_dynlock_value * dynlock = (struct CRYPTO_dynlock_value * )OPENSSL_malloc ((int )sizeof (struct CRYPTO_dynlock_value ));
513- rb_nativethread_lock_initialize (& dynlock -> lock );
522+ /* Do not use xmalloc() here, since it may raise NoMemoryError */
523+ struct CRYPTO_dynlock_value * dynlock =
524+ OPENSSL_malloc (sizeof (struct CRYPTO_dynlock_value ));
525+ if (dynlock )
526+ ossl_lock_init (dynlock );
514527 return dynlock ;
515528}
516529
517530static void
518531ossl_dyn_lock_callback (int mode , struct CRYPTO_dynlock_value * l , const char * file , int line )
519532{
520- ossl_lock_unlock (mode , & l -> lock );
533+ ossl_lock_unlock (mode , l );
521534}
522535
523536static void
@@ -541,21 +554,22 @@ static unsigned long ossl_thread_id(void)
541554}
542555#endif
543556
557+ static struct CRYPTO_dynlock_value * ossl_locks ;
558+
559+ static void
560+ ossl_lock_callback (int mode , int type , const char * file , int line )
561+ {
562+ ossl_lock_unlock (mode , & ossl_locks [type ]);
563+ }
564+
544565static void Init_ossl_locks (void )
545566{
546567 int i ;
547568 int num_locks = CRYPTO_num_locks ();
548569
549- if ((unsigned )num_locks >= INT_MAX / (int )sizeof (VALUE )) {
550- rb_raise (rb_eRuntimeError , "CRYPTO_num_locks() is too big: %d" , num_locks );
551- }
552- ossl_locks = (rb_nativethread_lock_t * ) OPENSSL_malloc (num_locks * (int )sizeof (rb_nativethread_lock_t ));
553- if (!ossl_locks ) {
554- rb_raise (rb_eNoMemError , "CRYPTO_num_locks() is too big: %d" , num_locks );
555- }
556- for (i = 0 ; i < num_locks ; i ++ ) {
557- rb_nativethread_lock_initialize (& ossl_locks [i ]);
558- }
570+ ossl_locks = ALLOC_N (struct CRYPTO_dynlock_value , num_locks );
571+ for (i = 0 ; i < num_locks ; i ++ )
572+ ossl_lock_init (& ossl_locks [i ]);
559573
560574#ifdef HAVE_CRYPTO_THREADID_PTR
561575 CRYPTO_THREADID_set_callback (ossl_threadid_func );
0 commit comments