https://github.com/python/cpython/commit/4a1389ced4ff39aececf5f696f617c3aeaa22a46
commit: 4a1389ced4ff39aececf5f696f617c3aeaa22a46
branch: 3.13
author: Tomasz Pytel <[email protected]>
committer: colesbury <[email protected]>
date: 2025-02-08T10:59:30-05:00
summary:
[3.13] gh-128657: fix _hashopenssl ref/data race (GH-128886) (GH-129853)
(cherry picked from commit 6c67904e793828d84716a8c83436c9495235f3a1)
files:
A Misc/NEWS.d/next/Library/2025-01-15-15-45-21.gh-issue-128657.P5LNQA.rst
M Modules/_hashopenssl.c
diff --git
a/Misc/NEWS.d/next/Library/2025-01-15-15-45-21.gh-issue-128657.P5LNQA.rst
b/Misc/NEWS.d/next/Library/2025-01-15-15-45-21.gh-issue-128657.P5LNQA.rst
new file mode 100644
index 00000000000000..3b08a9fba59620
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-01-15-15-45-21.gh-issue-128657.P5LNQA.rst
@@ -0,0 +1 @@
+Fix possible extra reference when using objects returned by
:func:`hashlib.sha256` under :term:`free threading`.
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
index d2e7630c22e7e9..a04dc26587ad99 100644
--- a/Modules/_hashopenssl.c
+++ b/Modules/_hashopenssl.c
@@ -25,14 +25,15 @@
#include <stdbool.h>
#include "Python.h"
#include "pycore_hashtable.h"
-#include "pycore_pyhash.h" // _Py_HashBytes()
-#include "pycore_strhex.h" // _Py_strhex()
+#include "pycore_pyhash.h" // _Py_HashBytes()
+#include "pycore_strhex.h" // _Py_strhex()
+#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_PTR_RELAXED
#include "hashlib.h"
/* EVP is the preferred interface to hashing in OpenSSL */
#include <openssl/evp.h>
#include <openssl/hmac.h>
-#include <openssl/crypto.h> // FIPS_mode()
+#include <openssl/crypto.h> // FIPS_mode()
/* We use the object interface to discover what hashes OpenSSL supports. */
#include <openssl/objects.h>
#include <openssl/err.h>
@@ -370,6 +371,7 @@ static PY_EVP_MD*
py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht)
{
PY_EVP_MD *digest = NULL;
+ PY_EVP_MD *other_digest = NULL;
_hashlibstate *state = get_hashlib_state(module);
py_hashentry_t *entry = (py_hashentry_t *)_Py_hashtable_get(
state->hashtable, (const void*)name
@@ -380,20 +382,36 @@ py_digest_by_name(PyObject *module, const char *name,
enum Py_hash_type py_ht)
case Py_ht_evp:
case Py_ht_mac:
case Py_ht_pbkdf2:
- if (entry->evp == NULL) {
- entry->evp = PY_EVP_MD_fetch(entry->ossl_name, NULL);
+ digest = FT_ATOMIC_LOAD_PTR_RELAXED(entry->evp);
+ if (digest == NULL) {
+ digest = PY_EVP_MD_fetch(entry->ossl_name, NULL);
+#ifdef Py_GIL_DISABLED
+ // exchange just in case another thread did same thing at same
time
+ other_digest = _Py_atomic_exchange_ptr(&entry->evp, digest);
+#else
+ entry->evp = digest;
+#endif
}
- digest = entry->evp;
break;
case Py_ht_evp_nosecurity:
- if (entry->evp_nosecurity == NULL) {
- entry->evp_nosecurity = PY_EVP_MD_fetch(entry->ossl_name,
"-fips");
+ digest = FT_ATOMIC_LOAD_PTR_RELAXED(entry->evp_nosecurity);
+ if (digest == NULL) {
+ digest = PY_EVP_MD_fetch(entry->ossl_name, "-fips");
+#ifdef Py_GIL_DISABLED
+ // exchange just in case another thread did same thing at same
time
+ other_digest = _Py_atomic_exchange_ptr(&entry->evp_nosecurity,
digest);
+#else
+ entry->evp_nosecurity = digest;
+#endif
}
- digest = entry->evp_nosecurity;
break;
}
+ // if another thread same thing at same time make sure we got same ptr
+ assert(other_digest == NULL || other_digest == digest);
if (digest != NULL) {
- PY_EVP_MD_up_ref(digest);
+ if (other_digest == NULL) {
+ PY_EVP_MD_up_ref(digest);
+ }
}
} else {
// Fall back for looking up an unindexed OpenSSL specific name.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]