2525#include <stdbool.h>
2626#include "Python.h"
2727#include "pycore_hashtable.h"
28- #include "pycore_pyhash.h" // _Py_HashBytes()
29- #include "pycore_strhex.h" // _Py_strhex()
28+ #include "pycore_pyhash.h" // _Py_HashBytes()
29+ #include "pycore_strhex.h" // _Py_strhex()
30+ #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_PTR_RELAXED
3031#include "hashlib.h"
3132
3233/* EVP is the preferred interface to hashing in OpenSSL */
3334#include <openssl/evp.h>
3435#include <openssl/hmac.h>
35- #include <openssl/crypto.h> // FIPS_mode()
36+ #include <openssl/crypto.h> // FIPS_mode()
3637/* We use the object interface to discover what hashes OpenSSL supports. */
3738#include <openssl/objects.h>
3839#include <openssl/err.h>
@@ -370,6 +371,7 @@ static PY_EVP_MD*
370371py_digest_by_name (PyObject * module , const char * name , enum Py_hash_type py_ht )
371372{
372373 PY_EVP_MD * digest = NULL ;
374+ PY_EVP_MD * other_digest = NULL ;
373375 _hashlibstate * state = get_hashlib_state (module );
374376 py_hashentry_t * entry = (py_hashentry_t * )_Py_hashtable_get (
375377 state -> hashtable , (const void * )name
@@ -380,20 +382,36 @@ py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht)
380382 case Py_ht_evp :
381383 case Py_ht_mac :
382384 case Py_ht_pbkdf2 :
383- if (entry -> evp == NULL ) {
384- entry -> evp = PY_EVP_MD_fetch (entry -> ossl_name , NULL );
385+ digest = FT_ATOMIC_LOAD_PTR_RELAXED (entry -> evp );
386+ if (digest == NULL ) {
387+ digest = PY_EVP_MD_fetch (entry -> ossl_name , NULL );
388+ #ifdef Py_GIL_DISABLED
389+ // exchange just in case another thread did same thing at same time
390+ other_digest = _Py_atomic_exchange_ptr (& entry -> evp , digest );
391+ #else
392+ entry -> evp = digest ;
393+ #endif
385394 }
386- digest = entry -> evp ;
387395 break ;
388396 case Py_ht_evp_nosecurity :
389- if (entry -> evp_nosecurity == NULL ) {
390- entry -> evp_nosecurity = PY_EVP_MD_fetch (entry -> ossl_name , "-fips" );
397+ digest = FT_ATOMIC_LOAD_PTR_RELAXED (entry -> evp_nosecurity );
398+ if (digest == NULL ) {
399+ digest = PY_EVP_MD_fetch (entry -> ossl_name , "-fips" );
400+ #ifdef Py_GIL_DISABLED
401+ // exchange just in case another thread did same thing at same time
402+ other_digest = _Py_atomic_exchange_ptr (& entry -> evp_nosecurity , digest );
403+ #else
404+ entry -> evp_nosecurity = digest ;
405+ #endif
391406 }
392- digest = entry -> evp_nosecurity ;
393407 break ;
394408 }
409+ // if another thread same thing at same time make sure we got same ptr
410+ assert (other_digest == NULL || other_digest == digest );
395411 if (digest != NULL ) {
396- PY_EVP_MD_up_ref (digest );
412+ if (other_digest == NULL ) {
413+ PY_EVP_MD_up_ref (digest );
414+ }
397415 }
398416 } else {
399417 // Fall back for looking up an unindexed OpenSSL specific name.
0 commit comments