25
25
#include <stdbool.h>
26
26
#include "Python.h"
27
27
#include "pycore_hashtable.h"
28
- #include "pycore_strhex.h" // _Py_strhex()
28
+ #include "pycore_strhex.h" // _Py_strhex()
29
+ #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_PTR_RELAXED
29
30
#include "hashlib.h"
30
31
31
32
/* EVP is the preferred interface to hashing in OpenSSL */
32
33
#include <openssl/evp.h>
33
34
#include <openssl/hmac.h>
34
- #include <openssl/crypto.h> // FIPS_mode()
35
+ #include <openssl/crypto.h> // FIPS_mode()
35
36
/* We use the object interface to discover what hashes OpenSSL supports. */
36
37
#include <openssl/objects.h>
37
38
#include <openssl/err.h>
@@ -369,6 +370,7 @@ static PY_EVP_MD*
369
370
py_digest_by_name (PyObject * module , const char * name , enum Py_hash_type py_ht )
370
371
{
371
372
PY_EVP_MD * digest = NULL ;
373
+ PY_EVP_MD * other_digest = NULL ;
372
374
_hashlibstate * state = get_hashlib_state (module );
373
375
py_hashentry_t * entry = (py_hashentry_t * )_Py_hashtable_get (
374
376
state -> hashtable , (const void * )name
@@ -379,20 +381,36 @@ py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht)
379
381
case Py_ht_evp :
380
382
case Py_ht_mac :
381
383
case Py_ht_pbkdf2 :
382
- if (entry -> evp == NULL ) {
383
- entry -> evp = PY_EVP_MD_fetch (entry -> ossl_name , NULL );
384
+ digest = FT_ATOMIC_LOAD_PTR_RELAXED (entry -> evp );
385
+ if (digest == NULL ) {
386
+ digest = PY_EVP_MD_fetch (entry -> ossl_name , NULL );
387
+ #ifdef Py_GIL_DISABLED
388
+ // exchange just in case another thread did same thing at same time
389
+ other_digest = _Py_atomic_exchange_ptr (& entry -> evp , digest );
390
+ #else
391
+ entry -> evp = digest ;
392
+ #endif
384
393
}
385
- digest = entry -> evp ;
386
394
break ;
387
395
case Py_ht_evp_nosecurity :
388
- if (entry -> evp_nosecurity == NULL ) {
389
- entry -> evp_nosecurity = PY_EVP_MD_fetch (entry -> ossl_name , "-fips" );
396
+ digest = FT_ATOMIC_LOAD_PTR_RELAXED (entry -> evp_nosecurity );
397
+ if (digest == NULL ) {
398
+ digest = PY_EVP_MD_fetch (entry -> ossl_name , "-fips" );
399
+ #ifdef Py_GIL_DISABLED
400
+ // exchange just in case another thread did same thing at same time
401
+ other_digest = _Py_atomic_exchange_ptr (& entry -> evp_nosecurity , digest );
402
+ #else
403
+ entry -> evp_nosecurity = digest ;
404
+ #endif
390
405
}
391
- digest = entry -> evp_nosecurity ;
392
406
break ;
393
407
}
408
+ // if another thread same thing at same time make sure we got same ptr
409
+ assert (other_digest == NULL || other_digest == digest );
394
410
if (digest != NULL ) {
395
- PY_EVP_MD_up_ref (digest );
411
+ if (other_digest == NULL ) {
412
+ PY_EVP_MD_up_ref (digest );
413
+ }
396
414
}
397
415
} else {
398
416
// Fall back for looking up an unindexed OpenSSL specific name.
0 commit comments