From bf791360bbe98679088442e461bf193f58f17129 Mon Sep 17 00:00:00 2001 From: Tomas Roun Date: Fri, 10 Nov 2023 15:53:34 +0100 Subject: [PATCH 01/11] WIP: Make hashlib thread-safe without the GIL --- Modules/_blake2/blake2b_impl.c | 31 +++++++++++------------ Modules/_blake2/blake2s_impl.c | 43 ++++++++++++++++--------------- Modules/_hashopenssl.c | 44 +++++++++++--------------------- Modules/hashlib.h | 34 +++++++++++++++++++------ Modules/md5module.c | 23 ++++++++--------- Modules/sha1module.c | 19 ++++++-------- Modules/sha2module.c | 46 +++++++++++++++------------------- Modules/sha3module.c | 23 ++++++++--------- 8 files changed, 127 insertions(+), 136 deletions(-) diff --git a/Modules/_blake2/blake2b_impl.c b/Modules/_blake2/blake2b_impl.c index c2cac98c7529eb..a6a3a21086bb3e 100644 --- a/Modules/_blake2/blake2b_impl.c +++ b/Modules/_blake2/blake2b_impl.c @@ -17,6 +17,7 @@ # define Py_BUILD_CORE_MODULE 1 #endif +#include #include "Python.h" #include "pycore_strhex.h" // _Py_strhex() @@ -42,7 +43,8 @@ typedef struct { PyObject_HEAD blake2b_param param; blake2b_state state; - PyThread_type_lock lock; + bool use_mutex; + PyMutex mutex; } BLAKE2bObject; #include "clinic/blake2b_impl.c.h" @@ -59,9 +61,11 @@ new_BLAKE2bObject(PyTypeObject *type) { BLAKE2bObject *self; self = (BLAKE2bObject *)type->tp_alloc(type, 0); - if (self != NULL) { - self->lock = NULL; + if (self == NULL) { + return NULL; } + INIT_MUTEX(self); + return self; } @@ -278,18 +282,17 @@ _blake2_blake2b_update(BLAKE2bObject *self, PyObject *data) GET_BUFFER_VIEW_OR_ERROUT(data, &buf); - if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) - self->lock = PyThread_allocate_lock(); - - if (self->lock != NULL) { - Py_BEGIN_ALLOW_THREADS - PyThread_acquire_lock(self->lock, 1); - blake2b_update(&self->state, buf.buf, buf.len); - PyThread_release_lock(self->lock); - Py_END_ALLOW_THREADS + self->use_mutex = true; + if (buf.len >= HASHLIB_GIL_MINSIZE) { + Py_BEGIN_ALLOW_THREADS + PyMutex_Lock(&self->mutex); + blake2b_update(&self->state, buf.buf, buf.len); + PyMutex_Unlock(&self->mutex); + Py_END_ALLOW_THREADS } else { blake2b_update(&self->state, buf.buf, buf.len); } + PyBuffer_Release(&buf); Py_RETURN_NONE; @@ -389,10 +392,6 @@ py_blake2b_dealloc(PyObject *self) /* Try not to leave state in memory. */ secure_zero_memory(&obj->param, sizeof(obj->param)); secure_zero_memory(&obj->state, sizeof(obj->state)); - if (obj->lock) { - PyThread_free_lock(obj->lock); - obj->lock = NULL; - } PyTypeObject *type = Py_TYPE(self); PyObject_Free(self); diff --git a/Modules/_blake2/blake2s_impl.c b/Modules/_blake2/blake2s_impl.c index 1c47328ece13e8..018daff2c242ce 100644 --- a/Modules/_blake2/blake2s_impl.c +++ b/Modules/_blake2/blake2s_impl.c @@ -17,6 +17,7 @@ # define Py_BUILD_CORE_MODULE 1 #endif +#include #include "Python.h" #include "pycore_strhex.h" // _Py_strhex() @@ -42,7 +43,8 @@ typedef struct { PyObject_HEAD blake2s_param param; blake2s_state state; - PyThread_type_lock lock; + bool use_mutex; + PyMutex mutex; } BLAKE2sObject; #include "clinic/blake2s_impl.c.h" @@ -51,7 +53,7 @@ typedef struct { module _blake2 class _blake2.blake2s "BLAKE2sObject *" "&PyBlake2_BLAKE2sType" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=4b79d7ffe07286ce]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d47b0527b39c673f]*/ static BLAKE2sObject * @@ -59,9 +61,11 @@ new_BLAKE2sObject(PyTypeObject *type) { BLAKE2sObject *self; self = (BLAKE2sObject *)type->tp_alloc(type, 0); - if (self != NULL) { - self->lock = NULL; + if (self == NULL) { + return NULL; } + INIT_MUTEX(self); + return self; } @@ -93,7 +97,7 @@ py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size, int fanout, int depth, unsigned long leaf_size, unsigned long long node_offset, int node_depth, int inner_size, int last_node, int usedforsecurity) -/*[clinic end generated code: output=556181f73905c686 input=4dda87723f23abb0]*/ +/*[clinic end generated code: output=32bfd8f043c6896f input=b947312abff46977]*/ { BLAKE2sObject *self = NULL; Py_buffer buf; @@ -247,7 +251,7 @@ Return a copy of the hash object. static PyObject * _blake2_blake2s_copy_impl(BLAKE2sObject *self) -/*[clinic end generated code: output=5b90131c4eae275e input=0b9d44942f0fe4b2]*/ +/*[clinic end generated code: output=ff6acee5f93656ae input=e383c2d199fd8a2e]*/ { BLAKE2sObject *cpy; @@ -272,24 +276,23 @@ Update this hash object's state with the provided bytes-like object. static PyObject * _blake2_blake2s_update(BLAKE2sObject *self, PyObject *data) -/*[clinic end generated code: output=757dc087fec37815 input=97500db2f9de4aaa]*/ +/*[clinic end generated code: output=010dfcbe22654359 input=ffc4aa6a6a225d31]*/ { Py_buffer buf; GET_BUFFER_VIEW_OR_ERROUT(data, &buf); - if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) - self->lock = PyThread_allocate_lock(); - - if (self->lock != NULL) { - Py_BEGIN_ALLOW_THREADS - PyThread_acquire_lock(self->lock, 1); - blake2s_update(&self->state, buf.buf, buf.len); - PyThread_release_lock(self->lock); - Py_END_ALLOW_THREADS + self->use_mutex = true; + if (buf.len >= HASHLIB_GIL_MINSIZE) { + Py_BEGIN_ALLOW_THREADS + PyMutex_Lock(&self->mutex); + blake2s_update(&self->state, buf.buf, buf.len); + PyMutex_Unlock(&self->mutex); + Py_END_ALLOW_THREADS } else { blake2s_update(&self->state, buf.buf, buf.len); } + PyBuffer_Release(&buf); Py_RETURN_NONE; @@ -303,7 +306,7 @@ Return the digest value as a bytes object. static PyObject * _blake2_blake2s_digest_impl(BLAKE2sObject *self) -/*[clinic end generated code: output=40c566ca4bc6bc51 input=f41e0b8d6d937454]*/ +/*[clinic end generated code: output=a5864660f4bfc61a input=7d21659e9c5fff02]*/ { uint8_t digest[BLAKE2S_OUTBYTES]; blake2s_state state_cpy; @@ -324,7 +327,7 @@ Return the digest value as a string of hexadecimal digits. static PyObject * _blake2_blake2s_hexdigest_impl(BLAKE2sObject *self) -/*[clinic end generated code: output=15153eb5e59c52eb input=c77a1321567e8952]*/ +/*[clinic end generated code: output=b5598a87d8794a60 input=76930f6946351f56]*/ { uint8_t digest[BLAKE2S_OUTBYTES]; blake2s_state state_cpy; @@ -389,10 +392,6 @@ py_blake2s_dealloc(PyObject *self) /* Try not to leave state in memory. */ secure_zero_memory(&obj->param, sizeof(obj->param)); secure_zero_memory(&obj->state, sizeof(obj->state)); - if (obj->lock) { - PyThread_free_lock(obj->lock); - obj->lock = NULL; - } PyTypeObject *type = Py_TYPE(self); PyObject_Free(self); diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index ee6fb8b4b03643..d92ff97b3b9c85 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -22,6 +22,7 @@ # define Py_BUILD_CORE_MODULE 1 #endif +#include #include "Python.h" #include "pycore_hashtable.h" #include "pycore_pyhash.h" // _Py_HashBytes() @@ -227,16 +228,16 @@ typedef struct { PyObject_HEAD EVP_MD_CTX *ctx; /* OpenSSL message digest context */ // Prevents undefined behavior via multiple threads entering the C API. - // The lock will be NULL before threaded access has been enabled. - PyThread_type_lock lock; /* OpenSSL context lock */ + bool use_mutex; + PyMutex mutex; } EVPobject; typedef struct { PyObject_HEAD HMAC_CTX *ctx; /* OpenSSL hmac context */ // Prevents undefined behavior via multiple threads entering the C API. - // The lock will be NULL before threaded access has been enabled. - PyThread_type_lock lock; /* HMAC context lock */ + bool use_mutex; + PyMutex mutex; } HMACobject; #include "clinic/_hashopenssl.c.h" @@ -414,8 +415,7 @@ newEVPobject(PyTypeObject *type) if (retval == NULL) { return NULL; } - - retval->lock = NULL; + INIT_MUTEX(retval); retval->ctx = EVP_MD_CTX_new(); if (retval->ctx == NULL) { @@ -453,8 +453,6 @@ static void EVP_dealloc(EVPobject *self) { PyTypeObject *tp = Py_TYPE(self); - if (self->lock != NULL) - PyThread_free_lock(self->lock); EVP_MD_CTX_free(self->ctx); PyObject_Free(self); Py_DECREF(tp); @@ -582,16 +580,11 @@ EVP_update(EVPobject *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &view); - if (self->lock == NULL && view.len >= HASHLIB_GIL_MINSIZE) { - self->lock = PyThread_allocate_lock(); - /* fail? lock = NULL and we fail over to non-threaded code. */ - } - - if (self->lock != NULL) { + if (self->use_mutex && view.len >= HASHLIB_GIL_MINSIZE) { Py_BEGIN_ALLOW_THREADS - PyThread_acquire_lock(self->lock, 1); + PyMutex_Lock(&self->mutex); result = EVP_hash(self, view.buf, view.len); - PyThread_release_lock(self->lock); + PyMutex_Unlock(&self->mutex); Py_END_ALLOW_THREADS } else { result = EVP_hash(self, view.buf, view.len); @@ -1540,7 +1533,7 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj, } self->ctx = ctx; - self->lock = NULL; + self->mutex = (PyMutex){0}; if ((msg_obj != NULL) && (msg_obj != Py_None)) { if (!_hmac_update(self, msg_obj)) @@ -1582,16 +1575,12 @@ _hmac_update(HMACobject *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROR(obj, &view, return 0); - if (self->lock == NULL && view.len >= HASHLIB_GIL_MINSIZE) { - self->lock = PyThread_allocate_lock(); - /* fail? lock = NULL and we fail over to non-threaded code. */ - } - - if (self->lock != NULL) { + self->use_mutex = true; + if (view.len >= HASHLIB_GIL_MINSIZE) { Py_BEGIN_ALLOW_THREADS - PyThread_acquire_lock(self->lock, 1); + PyMutex_Lock(&self->mutex); r = HMAC_Update(self->ctx, (const unsigned char*)view.buf, view.len); - PyThread_release_lock(self->lock); + PyMutex_Unlock(&self->mutex); Py_END_ALLOW_THREADS } else { r = HMAC_Update(self->ctx, (const unsigned char*)view.buf, view.len); @@ -1633,7 +1622,7 @@ _hashlib_HMAC_copy_impl(HMACobject *self) return NULL; } retval->ctx = ctx; - retval->lock = NULL; + retval->mutex = (PyMutex){0}; return (PyObject *)retval; } @@ -1642,9 +1631,6 @@ static void _hmac_dealloc(HMACobject *self) { PyTypeObject *tp = Py_TYPE(self); - if (self->lock != NULL) { - PyThread_free_lock(self->lock); - } HMAC_CTX_free(self->ctx); PyObject_Free(self); Py_DECREF(tp); diff --git a/Modules/hashlib.h b/Modules/hashlib.h index a8bad9dd87a939..5c0c33b1e5b68f 100644 --- a/Modules/hashlib.h +++ b/Modules/hashlib.h @@ -1,5 +1,11 @@ /* Common code for use by all hashlib related modules. */ +#ifndef Py_BUILD_CORE +#define Py_BUILD_CORE +#endif + +#include "pycore_lock.h" // PyMutex + /* * Given a PyObject* obj, fill in the Py_buffer* viewp with the result * of PyObject_GetBuffer. Sets an exception and issues the erraction @@ -48,18 +54,30 @@ #include "pythread.h" #define ENTER_HASHLIB(obj) \ - if ((obj)->lock) { \ - if (!PyThread_acquire_lock((obj)->lock, 0)) { \ - Py_BEGIN_ALLOW_THREADS \ - PyThread_acquire_lock((obj)->lock, 1); \ - Py_END_ALLOW_THREADS \ - } \ + if ((obj)->use_mutex) { \ + Py_BEGIN_ALLOW_THREADS \ + PyMutex_Lock(&(obj)->mutex); \ + Py_END_ALLOW_THREADS \ } #define LEAVE_HASHLIB(obj) \ - if ((obj)->lock) { \ - PyThread_release_lock((obj)->lock); \ + if ((obj)->use_mutex) { \ + PyMutex_Unlock(&(obj)->mutex); \ } +#ifdef Py_NOGIL +#define INIT_MUTEX(obj) \ + do { \ + (obj)->mutex = (PyMutex){0}; \ + (obj)->use_mutex = true; \ + } while (0) +#else +#define INIT_MUTEX(obj) \ + do { \ + (obj)->mutex = (PyMutex){0}; \ + (obj)->use_mutex = false; \ + } while (0) +#endif + /* TODO(gpshead): We should make this a module or class attribute * to allow the user to optimize based on the platform they're using. */ #define HASHLIB_GIL_MINSIZE 2048 diff --git a/Modules/md5module.c b/Modules/md5module.c index 7883a8cbe6e246..cbb7b6b1fc8bab 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -54,8 +54,8 @@ typedef long long MD5_INT64; /* 64-bit integer */ typedef struct { PyObject_HEAD // Prevents undefined behavior via multiple threads entering the C API. - // The lock will be NULL before threaded access has been enabled. - PyThread_type_lock lock; + bool use_mutex; + PyMutex mutex; Hacl_Streaming_MD5_state *hash_state; } MD5object; @@ -78,7 +78,11 @@ static MD5object * newMD5object(MD5State * st) { MD5object *md5 = (MD5object *)PyObject_GC_New(MD5object, st->md5_type); - md5->lock = NULL; + if(!md5) { + return NULL; + } + INIT_MUTEX(md5); + PyObject_GC_Track(md5); return md5; } @@ -95,9 +99,6 @@ static void MD5_dealloc(MD5object *ptr) { Hacl_Streaming_MD5_legacy_free(ptr->hash_state); - if (ptr->lock != NULL) { - PyThread_free_lock(ptr->lock); - } PyTypeObject *tp = Py_TYPE((PyObject*)ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -202,14 +203,12 @@ MD5Type_update(MD5object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { - self->lock = PyThread_allocate_lock(); - } - if (self->lock != NULL) { + self->use_mutex = true; + if (buf.len >= HASHLIB_GIL_MINSIZE) { Py_BEGIN_ALLOW_THREADS - PyThread_acquire_lock(self->lock, 1); + PyMutex_Lock(&self->mutex); update(self->hash_state, buf.buf, buf.len); - PyThread_release_lock(self->lock); + PyMutex_Unlock(&self->mutex); Py_END_ALLOW_THREADS } else { update(self->hash_state, buf.buf, buf.len); diff --git a/Modules/sha1module.c b/Modules/sha1module.c index 3fd53123229ac4..28ac1f881111ff 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -49,7 +49,8 @@ typedef long long SHA1_INT64; /* 64-bit integer */ typedef struct { PyObject_HEAD // Prevents undefined behavior via multiple threads entering the C API. - // The lock will be NULL before threaded access has been enabled. + bool use_mutex; + PyMutex mutex; PyThread_type_lock lock; Hacl_Streaming_SHA1_state *hash_state; } SHA1object; @@ -76,7 +77,8 @@ newSHA1object(SHA1State *st) if (sha == NULL) { return NULL; } - sha->lock = NULL; + INIT_MUTEX(sha); + PyObject_GC_Track(sha); return sha; } @@ -94,9 +96,6 @@ static void SHA1_dealloc(SHA1object *ptr) { Hacl_Streaming_SHA1_legacy_free(ptr->hash_state); - if (ptr->lock != NULL) { - PyThread_free_lock(ptr->lock); - } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -192,14 +191,12 @@ SHA1Type_update(SHA1object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { - self->lock = PyThread_allocate_lock(); - } - if (self->lock != NULL) { + self->use_mutex = true; + if (buf.len >= HASHLIB_GIL_MINSIZE) { Py_BEGIN_ALLOW_THREADS - PyThread_acquire_lock(self->lock, 1); + PyMutex_Lock(&self->mutex); update(self->hash_state, buf.buf, buf.len); - PyThread_release_lock(self->lock); + PyMutex_Unlock(&self->mutex); Py_END_ALLOW_THREADS } else { update(self->hash_state, buf.buf, buf.len); diff --git a/Modules/sha2module.c b/Modules/sha2module.c index 6ad1ff2e05bfd8..9dc87203f24cbe 100644 --- a/Modules/sha2module.c +++ b/Modules/sha2module.c @@ -53,8 +53,8 @@ typedef struct { PyObject_HEAD int digestsize; // Prevents undefined behavior via multiple threads entering the C API. - // The lock will be NULL before threaded access has been enabled. - PyThread_type_lock lock; + bool use_mutex; + PyMutex mutex; Hacl_Streaming_SHA2_state_sha2_256 *state; } SHA256object; @@ -62,8 +62,8 @@ typedef struct { PyObject_HEAD int digestsize; // Prevents undefined behavior via multiple threads entering the C API. - // The lock will be NULL before threaded access has been enabled. - PyThread_type_lock lock; + bool use_mutex; + PyMutex mutex; Hacl_Streaming_SHA2_state_sha2_512 *state; } SHA512object; @@ -106,7 +106,8 @@ newSHA224object(sha2_state *state) if (!sha) { return NULL; } - sha->lock = NULL; + INIT_MUTEX(sha); + PyObject_GC_Track(sha); return sha; } @@ -119,7 +120,8 @@ newSHA256object(sha2_state *state) if (!sha) { return NULL; } - sha->lock = NULL; + INIT_MUTEX(sha); + PyObject_GC_Track(sha); return sha; } @@ -132,7 +134,8 @@ newSHA384object(sha2_state *state) if (!sha) { return NULL; } - sha->lock = NULL; + INIT_MUTEX(sha); + PyObject_GC_Track(sha); return sha; } @@ -145,7 +148,8 @@ newSHA512object(sha2_state *state) if (!sha) { return NULL; } - sha->lock = NULL; + INIT_MUTEX(sha); + PyObject_GC_Track(sha); return sha; } @@ -163,9 +167,6 @@ static void SHA256_dealloc(SHA256object *ptr) { Hacl_Streaming_SHA2_free_256(ptr->state); - if (ptr->lock != NULL) { - PyThread_free_lock(ptr->lock); - } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -176,9 +177,6 @@ static void SHA512_dealloc(SHA512object *ptr) { Hacl_Streaming_SHA2_free_512(ptr->state); - if (ptr->lock != NULL) { - PyThread_free_lock(ptr->lock); - } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -376,14 +374,12 @@ SHA256Type_update(SHA256object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { - self->lock = PyThread_allocate_lock(); - } - if (self->lock != NULL) { + self->use_mutex = true; + if (buf.len >= HASHLIB_GIL_MINSIZE) { Py_BEGIN_ALLOW_THREADS - PyThread_acquire_lock(self->lock, 1); + PyMutex_Lock(&self->mutex); update_256(self->state, buf.buf, buf.len); - PyThread_release_lock(self->lock); + PyMutex_Unlock(&self->mutex); Py_END_ALLOW_THREADS } else { update_256(self->state, buf.buf, buf.len); @@ -410,14 +406,12 @@ SHA512Type_update(SHA512object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { - self->lock = PyThread_allocate_lock(); - } - if (self->lock != NULL) { + self->use_mutex = true; + if (buf.len >= HASHLIB_GIL_MINSIZE) { Py_BEGIN_ALLOW_THREADS - PyThread_acquire_lock(self->lock, 1); + PyMutex_Lock(&self->mutex); update_512(self->state, buf.buf, buf.len); - PyThread_release_lock(self->lock); + PyMutex_Unlock(&self->mutex); Py_END_ALLOW_THREADS } else { update_512(self->state, buf.buf, buf.len); diff --git a/Modules/sha3module.c b/Modules/sha3module.c index 558d2005cff617..933e6fafd85b28 100644 --- a/Modules/sha3module.c +++ b/Modules/sha3module.c @@ -61,8 +61,8 @@ class _sha3.shake_256 "SHA3object *" "&SHAKE256type" typedef struct { PyObject_HEAD // Prevents undefined behavior via multiple threads entering the C API. - // The lock will be NULL before threaded access has been enabled. - PyThread_type_lock lock; + bool use_mutex; + PyMutex mutex; Hacl_Streaming_Keccak_state *hash_state; } SHA3object; @@ -76,7 +76,8 @@ newSHA3object(PyTypeObject *type) if (newobj == NULL) { return NULL; } - newobj->lock = NULL; + INIT_MUTEX(newobj); + return newobj; } @@ -169,9 +170,6 @@ static void SHA3_dealloc(SHA3object *self) { Hacl_Streaming_Keccak_free(self->hash_state); - if (self->lock != NULL) { - PyThread_free_lock(self->lock); - } PyTypeObject *tp = Py_TYPE(self); PyObject_Free(self); Py_DECREF(tp); @@ -257,19 +255,20 @@ _sha3_sha3_224_update(SHA3object *self, PyObject *data) /*[clinic end generated code: output=d3223352286ed357 input=a887f54dcc4ae227]*/ { Py_buffer buf; + GET_BUFFER_VIEW_OR_ERROUT(data, &buf); - if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { - self->lock = PyThread_allocate_lock(); - } - if (self->lock != NULL) { + + self->use_mutex = true; + if (buf.len >= HASHLIB_GIL_MINSIZE) { Py_BEGIN_ALLOW_THREADS - PyThread_acquire_lock(self->lock, 1); + PyMutex_Lock(&self->mutex); sha3_update(self->hash_state, buf.buf, buf.len); - PyThread_release_lock(self->lock); + PyMutex_Unlock(&self->mutex); Py_END_ALLOW_THREADS } else { sha3_update(self->hash_state, buf.buf, buf.len); } + PyBuffer_Release(&buf); Py_RETURN_NONE; } From 00a1aa38e00366dc80d7e1e684a5d3733734fe21 Mon Sep 17 00:00:00 2001 From: Tomas Roun Date: Tue, 14 Nov 2023 21:39:35 +0100 Subject: [PATCH 02/11] Fix 'ENTER_HASHLIB' macro --- Modules/hashlib.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Modules/hashlib.h b/Modules/hashlib.h index 5c0c33b1e5b68f..b273c05f428b91 100644 --- a/Modules/hashlib.h +++ b/Modules/hashlib.h @@ -55,9 +55,7 @@ #include "pythread.h" #define ENTER_HASHLIB(obj) \ if ((obj)->use_mutex) { \ - Py_BEGIN_ALLOW_THREADS \ PyMutex_Lock(&(obj)->mutex); \ - Py_END_ALLOW_THREADS \ } #define LEAVE_HASHLIB(obj) \ if ((obj)->use_mutex) { \ From 68e7934f00c4df73a467910bae2455542c8b9e5c Mon Sep 17 00:00:00 2001 From: Tomas Roun Date: Tue, 14 Nov 2023 21:42:06 +0100 Subject: [PATCH 03/11] Rename INIT_MUTEX --- Modules/_blake2/blake2b_impl.c | 2 +- Modules/_blake2/blake2s_impl.c | 2 +- Modules/_hashopenssl.c | 2 +- Modules/hashlib.h | 4 ++-- Modules/md5module.c | 2 +- Modules/sha1module.c | 2 +- Modules/sha2module.c | 8 ++++---- Modules/sha3module.c | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Modules/_blake2/blake2b_impl.c b/Modules/_blake2/blake2b_impl.c index a6a3a21086bb3e..a559e590e7c854 100644 --- a/Modules/_blake2/blake2b_impl.c +++ b/Modules/_blake2/blake2b_impl.c @@ -64,7 +64,7 @@ new_BLAKE2bObject(PyTypeObject *type) if (self == NULL) { return NULL; } - INIT_MUTEX(self); + HASHLIB_INIT_MUTEX(self); return self; } diff --git a/Modules/_blake2/blake2s_impl.c b/Modules/_blake2/blake2s_impl.c index 018daff2c242ce..06af99b2e0ed67 100644 --- a/Modules/_blake2/blake2s_impl.c +++ b/Modules/_blake2/blake2s_impl.c @@ -64,7 +64,7 @@ new_BLAKE2sObject(PyTypeObject *type) if (self == NULL) { return NULL; } - INIT_MUTEX(self); + HASHLIB_INIT_MUTEX(self); return self; } diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index d92ff97b3b9c85..86eebc27842f4e 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -415,7 +415,7 @@ newEVPobject(PyTypeObject *type) if (retval == NULL) { return NULL; } - INIT_MUTEX(retval); + HASHLIB_INIT_MUTEX(retval); retval->ctx = EVP_MD_CTX_new(); if (retval->ctx == NULL) { diff --git a/Modules/hashlib.h b/Modules/hashlib.h index b273c05f428b91..76cdb49c534ba9 100644 --- a/Modules/hashlib.h +++ b/Modules/hashlib.h @@ -63,13 +63,13 @@ } #ifdef Py_NOGIL -#define INIT_MUTEX(obj) \ +#define HASHLIB_INIT_MUTEX(obj) \ do { \ (obj)->mutex = (PyMutex){0}; \ (obj)->use_mutex = true; \ } while (0) #else -#define INIT_MUTEX(obj) \ +#define HASHLIB_INIT_MUTEX(obj) \ do { \ (obj)->mutex = (PyMutex){0}; \ (obj)->use_mutex = false; \ diff --git a/Modules/md5module.c b/Modules/md5module.c index cbb7b6b1fc8bab..aab43ab6ab1a72 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -81,7 +81,7 @@ newMD5object(MD5State * st) if(!md5) { return NULL; } - INIT_MUTEX(md5); + HASHLIB_INIT_MUTEX(md5); PyObject_GC_Track(md5); return md5; diff --git a/Modules/sha1module.c b/Modules/sha1module.c index 28ac1f881111ff..ca64ab8d410cbc 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -77,7 +77,7 @@ newSHA1object(SHA1State *st) if (sha == NULL) { return NULL; } - INIT_MUTEX(sha); + HASHLIB_INIT_MUTEX(sha); PyObject_GC_Track(sha); return sha; diff --git a/Modules/sha2module.c b/Modules/sha2module.c index 9dc87203f24cbe..09f5d125fccb5d 100644 --- a/Modules/sha2module.c +++ b/Modules/sha2module.c @@ -106,7 +106,7 @@ newSHA224object(sha2_state *state) if (!sha) { return NULL; } - INIT_MUTEX(sha); + HASHLIB_INIT_MUTEX(sha); PyObject_GC_Track(sha); return sha; @@ -120,7 +120,7 @@ newSHA256object(sha2_state *state) if (!sha) { return NULL; } - INIT_MUTEX(sha); + HASHLIB_INIT_MUTEX(sha); PyObject_GC_Track(sha); return sha; @@ -134,7 +134,7 @@ newSHA384object(sha2_state *state) if (!sha) { return NULL; } - INIT_MUTEX(sha); + HASHLIB_INIT_MUTEX(sha); PyObject_GC_Track(sha); return sha; @@ -148,7 +148,7 @@ newSHA512object(sha2_state *state) if (!sha) { return NULL; } - INIT_MUTEX(sha); + HASHLIB_INIT_MUTEX(sha); PyObject_GC_Track(sha); return sha; diff --git a/Modules/sha3module.c b/Modules/sha3module.c index 933e6fafd85b28..ee96569c9cde59 100644 --- a/Modules/sha3module.c +++ b/Modules/sha3module.c @@ -76,7 +76,7 @@ newSHA3object(PyTypeObject *type) if (newobj == NULL) { return NULL; } - INIT_MUTEX(newobj); + HASHLIB_INIT_MUTEX(newobj); return newobj; } From d04b2ec71fcd4056ea4e0e10f5143f936f6f0aee Mon Sep 17 00:00:00 2001 From: Tomas Roun Date: Tue, 14 Nov 2023 21:54:55 +0100 Subject: [PATCH 04/11] Fix 'use_mutex' logic --- Modules/_blake2/blake2b_impl.c | 6 ++++-- Modules/_blake2/blake2s_impl.c | 6 ++++-- Modules/_hashopenssl.c | 13 +++++++++---- Modules/md5module.c | 6 ++++-- Modules/sha1module.c | 6 ++++-- Modules/sha2module.c | 12 ++++++++---- Modules/sha3module.c | 6 ++++-- 7 files changed, 37 insertions(+), 18 deletions(-) diff --git a/Modules/_blake2/blake2b_impl.c b/Modules/_blake2/blake2b_impl.c index a559e590e7c854..0c3ae5a2fac275 100644 --- a/Modules/_blake2/blake2b_impl.c +++ b/Modules/_blake2/blake2b_impl.c @@ -282,8 +282,10 @@ _blake2_blake2b_update(BLAKE2bObject *self, PyObject *data) GET_BUFFER_VIEW_OR_ERROUT(data, &buf); - self->use_mutex = true; - if (buf.len >= HASHLIB_GIL_MINSIZE) { + if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) { + self->use_mutex = true; + } + if (self->use_mutex) { Py_BEGIN_ALLOW_THREADS PyMutex_Lock(&self->mutex); blake2b_update(&self->state, buf.buf, buf.len); diff --git a/Modules/_blake2/blake2s_impl.c b/Modules/_blake2/blake2s_impl.c index 06af99b2e0ed67..d0b9337e089c65 100644 --- a/Modules/_blake2/blake2s_impl.c +++ b/Modules/_blake2/blake2s_impl.c @@ -282,8 +282,10 @@ _blake2_blake2s_update(BLAKE2sObject *self, PyObject *data) GET_BUFFER_VIEW_OR_ERROUT(data, &buf); - self->use_mutex = true; - if (buf.len >= HASHLIB_GIL_MINSIZE) { + if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) { + self->use_mutex = true; + } + if (self->use_mutex) { Py_BEGIN_ALLOW_THREADS PyMutex_Lock(&self->mutex); blake2s_update(&self->state, buf.buf, buf.len); diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 86eebc27842f4e..2774dd4d711c52 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -580,7 +580,10 @@ EVP_update(EVPobject *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &view); - if (self->use_mutex && view.len >= HASHLIB_GIL_MINSIZE) { + if (!self->use_mutex && view.len >= HASHLIB_GIL_MINSIZE) { + self->use_mutex = true; + } + if (self->use_mutex) { Py_BEGIN_ALLOW_THREADS PyMutex_Lock(&self->mutex); result = EVP_hash(self, view.buf, view.len); @@ -1533,7 +1536,7 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj, } self->ctx = ctx; - self->mutex = (PyMutex){0}; + HASHLIB_INIT_MUTEX(self); if ((msg_obj != NULL) && (msg_obj != Py_None)) { if (!_hmac_update(self, msg_obj)) @@ -1575,8 +1578,10 @@ _hmac_update(HMACobject *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROR(obj, &view, return 0); - self->use_mutex = true; - if (view.len >= HASHLIB_GIL_MINSIZE) { + if (!self->use_mutex && view.len >= HASHLIB_GIL_MINSIZE) { + self->use_mutex = true; + } + if (self->use_mutex) { Py_BEGIN_ALLOW_THREADS PyMutex_Lock(&self->mutex); r = HMAC_Update(self->ctx, (const unsigned char*)view.buf, view.len); diff --git a/Modules/md5module.c b/Modules/md5module.c index aab43ab6ab1a72..cfb3da59c70ad4 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -203,8 +203,10 @@ MD5Type_update(MD5object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - self->use_mutex = true; - if (buf.len >= HASHLIB_GIL_MINSIZE) { + if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) { + self->use_mutex = true; + } + if (self->use_mutex) { Py_BEGIN_ALLOW_THREADS PyMutex_Lock(&self->mutex); update(self->hash_state, buf.buf, buf.len); diff --git a/Modules/sha1module.c b/Modules/sha1module.c index ca64ab8d410cbc..eda6b5608d52f7 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -191,8 +191,10 @@ SHA1Type_update(SHA1object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - self->use_mutex = true; - if (buf.len >= HASHLIB_GIL_MINSIZE) { + if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) { + self->use_mutex = true; + } + if (self->use_mutex) { Py_BEGIN_ALLOW_THREADS PyMutex_Lock(&self->mutex); update(self->hash_state, buf.buf, buf.len); diff --git a/Modules/sha2module.c b/Modules/sha2module.c index 09f5d125fccb5d..968493ba51b50d 100644 --- a/Modules/sha2module.c +++ b/Modules/sha2module.c @@ -374,8 +374,10 @@ SHA256Type_update(SHA256object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - self->use_mutex = true; - if (buf.len >= HASHLIB_GIL_MINSIZE) { + if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) { + self->use_mutex = true; + } + if (self->use_mutex) { Py_BEGIN_ALLOW_THREADS PyMutex_Lock(&self->mutex); update_256(self->state, buf.buf, buf.len); @@ -406,8 +408,10 @@ SHA512Type_update(SHA512object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - self->use_mutex = true; - if (buf.len >= HASHLIB_GIL_MINSIZE) { + if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) { + self->use_mutex = true; + } + if (self->use_mutex) { Py_BEGIN_ALLOW_THREADS PyMutex_Lock(&self->mutex); update_512(self->state, buf.buf, buf.len); diff --git a/Modules/sha3module.c b/Modules/sha3module.c index ee96569c9cde59..d9d2f6c385a68b 100644 --- a/Modules/sha3module.c +++ b/Modules/sha3module.c @@ -258,8 +258,10 @@ _sha3_sha3_224_update(SHA3object *self, PyObject *data) GET_BUFFER_VIEW_OR_ERROUT(data, &buf); - self->use_mutex = true; - if (buf.len >= HASHLIB_GIL_MINSIZE) { + if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) { + self->use_mutex = true; + } + if (self->use_mutex) { Py_BEGIN_ALLOW_THREADS PyMutex_Lock(&self->mutex); sha3_update(self->hash_state, buf.buf, buf.len); From bcb7fde224f33fee380a2accaa0bb4bb7754de60 Mon Sep 17 00:00:00 2001 From: Tomas Roun Date: Tue, 14 Nov 2023 21:55:13 +0100 Subject: [PATCH 05/11] Fix build errors --- Modules/md5module.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Modules/md5module.c b/Modules/md5module.c index cfb3da59c70ad4..6eeae096d37080 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -16,13 +16,8 @@ /* MD5 objects */ -#ifndef _MSC_VER -#include "pyconfig.h" // Py_NOGIL -#endif - -#ifndef Py_NOGIL -// Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED -#define Py_LIMITED_API 0x030c0000 +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 #endif #include "Python.h" From a4d816a113ddb2ce19da0db3d99275322d170b35 Mon Sep 17 00:00:00 2001 From: Tomas Roun Date: Tue, 14 Nov 2023 22:01:12 +0100 Subject: [PATCH 06/11] Remove unnecessary #define --- Modules/hashlib.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Modules/hashlib.h b/Modules/hashlib.h index 76cdb49c534ba9..25b2aaadfb2868 100644 --- a/Modules/hashlib.h +++ b/Modules/hashlib.h @@ -1,9 +1,5 @@ /* Common code for use by all hashlib related modules. */ -#ifndef Py_BUILD_CORE -#define Py_BUILD_CORE -#endif - #include "pycore_lock.h" // PyMutex /* From c8b6219309203f1c325cba6c25b6190fe179aa4b Mon Sep 17 00:00:00 2001 From: Tomas Roun Date: Tue, 14 Nov 2023 22:10:05 +0100 Subject: [PATCH 07/11] Reinitialize mutex when copying an HMAC object --- Modules/_hashopenssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 2774dd4d711c52..8de9df0be62e40 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -1627,7 +1627,7 @@ _hashlib_HMAC_copy_impl(HMACobject *self) return NULL; } retval->ctx = ctx; - retval->mutex = (PyMutex){0}; + HASHLIB_INIT_MUTEX(retval); return (PyObject *)retval; } From c58160a38b5ef37d44e040384fad77c702a056fd Mon Sep 17 00:00:00 2001 From: Tomas Roun Date: Tue, 14 Nov 2023 22:12:33 +0100 Subject: [PATCH 08/11] Add news entry --- .../2023-11-14-22-12-11.gh-issue-111916.ZGCayL.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-11-14-22-12-11.gh-issue-111916.ZGCayL.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-11-14-22-12-11.gh-issue-111916.ZGCayL.rst b/Misc/NEWS.d/next/Core and Builtins/2023-11-14-22-12-11.gh-issue-111916.ZGCayL.rst new file mode 100644 index 00000000000000..b3814828e476b9 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-11-14-22-12-11.gh-issue-111916.ZGCayL.rst @@ -0,0 +1 @@ +Make hashlib related modules thread-safe without the GIL From cfba91323a89c08af25167b227dd2662816385fb Mon Sep 17 00:00:00 2001 From: Tomas Roun Date: Wed, 15 Nov 2023 18:20:32 +0100 Subject: [PATCH 09/11] Re-add some comments --- Modules/_hashopenssl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 8de9df0be62e40..0e230f332ff6cb 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -229,7 +229,7 @@ typedef struct { EVP_MD_CTX *ctx; /* OpenSSL message digest context */ // Prevents undefined behavior via multiple threads entering the C API. bool use_mutex; - PyMutex mutex; + PyMutex mutex; /* OpenSSL context lock */ } EVPobject; typedef struct { @@ -237,7 +237,7 @@ typedef struct { HMAC_CTX *ctx; /* OpenSSL hmac context */ // Prevents undefined behavior via multiple threads entering the C API. bool use_mutex; - PyMutex mutex; + PyMutex mutex; /* HMAC context lock */ } HMACobject; #include "clinic/_hashopenssl.c.h" From 804318c3ea3af6f5c477c1e309e675726a5b7a6e Mon Sep 17 00:00:00 2001 From: Tomas Roun Date: Wed, 15 Nov 2023 18:24:12 +0100 Subject: [PATCH 10/11] Rerun argument clinic --- Modules/_blake2/blake2s_impl.c | 12 +++---- Modules/clinic/md5module.c.h | 65 ++++++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/Modules/_blake2/blake2s_impl.c b/Modules/_blake2/blake2s_impl.c index d0b9337e089c65..3014773ab52331 100644 --- a/Modules/_blake2/blake2s_impl.c +++ b/Modules/_blake2/blake2s_impl.c @@ -53,7 +53,7 @@ typedef struct { module _blake2 class _blake2.blake2s "BLAKE2sObject *" "&PyBlake2_BLAKE2sType" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d47b0527b39c673f]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=4b79d7ffe07286ce]*/ static BLAKE2sObject * @@ -97,7 +97,7 @@ py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size, int fanout, int depth, unsigned long leaf_size, unsigned long long node_offset, int node_depth, int inner_size, int last_node, int usedforsecurity) -/*[clinic end generated code: output=32bfd8f043c6896f input=b947312abff46977]*/ +/*[clinic end generated code: output=556181f73905c686 input=4dda87723f23abb0]*/ { BLAKE2sObject *self = NULL; Py_buffer buf; @@ -251,7 +251,7 @@ Return a copy of the hash object. static PyObject * _blake2_blake2s_copy_impl(BLAKE2sObject *self) -/*[clinic end generated code: output=ff6acee5f93656ae input=e383c2d199fd8a2e]*/ +/*[clinic end generated code: output=5b90131c4eae275e input=0b9d44942f0fe4b2]*/ { BLAKE2sObject *cpy; @@ -276,7 +276,7 @@ Update this hash object's state with the provided bytes-like object. static PyObject * _blake2_blake2s_update(BLAKE2sObject *self, PyObject *data) -/*[clinic end generated code: output=010dfcbe22654359 input=ffc4aa6a6a225d31]*/ +/*[clinic end generated code: output=757dc087fec37815 input=97500db2f9de4aaa]*/ { Py_buffer buf; @@ -308,7 +308,7 @@ Return the digest value as a bytes object. static PyObject * _blake2_blake2s_digest_impl(BLAKE2sObject *self) -/*[clinic end generated code: output=a5864660f4bfc61a input=7d21659e9c5fff02]*/ +/*[clinic end generated code: output=40c566ca4bc6bc51 input=f41e0b8d6d937454]*/ { uint8_t digest[BLAKE2S_OUTBYTES]; blake2s_state state_cpy; @@ -329,7 +329,7 @@ Return the digest value as a string of hexadecimal digits. static PyObject * _blake2_blake2s_hexdigest_impl(BLAKE2sObject *self) -/*[clinic end generated code: output=b5598a87d8794a60 input=76930f6946351f56]*/ +/*[clinic end generated code: output=15153eb5e59c52eb input=c77a1321567e8952]*/ { uint8_t digest[BLAKE2S_OUTBYTES]; blake2s_state state_cpy; diff --git a/Modules/clinic/md5module.c.h b/Modules/clinic/md5module.c.h index 1d98c574929f6f..7d4d3108dab9b6 100644 --- a/Modules/clinic/md5module.c.h +++ b/Modules/clinic/md5module.c.h @@ -2,6 +2,12 @@ preserve [clinic start generated code]*/ +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif +#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() + PyDoc_STRVAR(MD5Type_copy__doc__, "copy($self, /)\n" "--\n" @@ -9,7 +15,7 @@ PyDoc_STRVAR(MD5Type_copy__doc__, "Return a copy of the hash object."); #define MD5TYPE_COPY_METHODDEF \ - {"copy", (PyCFunction)(void(*)(void))MD5Type_copy, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, MD5Type_copy__doc__}, + {"copy", _PyCFunction_CAST(MD5Type_copy), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, MD5Type_copy__doc__}, static PyObject * MD5Type_copy_impl(MD5object *self, PyTypeObject *cls); @@ -76,25 +82,70 @@ PyDoc_STRVAR(_md5_md5__doc__, "Return a new MD5 hash object; optionally initialized with a string."); #define _MD5_MD5_METHODDEF \ - {"md5", (PyCFunction)(void(*)(void))_md5_md5, METH_VARARGS|METH_KEYWORDS, _md5_md5__doc__}, + {"md5", _PyCFunction_CAST(_md5_md5), METH_FASTCALL|METH_KEYWORDS, _md5_md5__doc__}, static PyObject * _md5_md5_impl(PyObject *module, PyObject *string, int usedforsecurity); static PyObject * -_md5_md5(PyObject *module, PyObject *args, PyObject *kwargs) +_md5_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; - static char *_keywords[] = {"string", "usedforsecurity", NULL}; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(string), &_Py_ID(usedforsecurity), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "md5", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; PyObject *string = NULL; int usedforsecurity = 1; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O$p:md5", _keywords, - &string, &usedforsecurity)) + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + string = args[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + usedforsecurity = PyObject_IsTrue(args[1]); + if (usedforsecurity < 0) { + goto exit; + } +skip_optional_kwonly: return_value = _md5_md5_impl(module, string, usedforsecurity); exit: return return_value; } -/*[clinic end generated code: output=81702ec915f36236 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=bfadda44914804a8 input=a9049054013a1b77]*/ From f7c419f06f2f79370c7e36943b2bbaf4366b0b20 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith [Google LLC]" Date: Wed, 15 Nov 2023 15:31:23 -0800 Subject: [PATCH 11/11] style: add missing space. --- Modules/md5module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/md5module.c b/Modules/md5module.c index 6eeae096d37080..7d2b3275f213fd 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -73,7 +73,7 @@ static MD5object * newMD5object(MD5State * st) { MD5object *md5 = (MD5object *)PyObject_GC_New(MD5object, st->md5_type); - if(!md5) { + if (!md5) { return NULL; } HASHLIB_INIT_MUTEX(md5);