Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
Make hashlib related modules thread-safe without the GIL
33 changes: 17 additions & 16 deletions Modules/_blake2/blake2b_impl.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,7 @@
# define Py_BUILD_CORE_MODULE 1
#endif

#include <stdbool.h>
#include "Python.h"
#include "pycore_strhex.h" // _Py_strhex()

Expand All@@ -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"
Expand All@@ -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;
}
HASHLIB_INIT_MUTEX(self);

return self;
}

Expand DownExpand Up@@ -278,18 +282,19 @@ _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
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);
PyMutex_Unlock(&self->mutex);
Py_END_ALLOW_THREADS
} else {
blake2b_update(&self->state, buf.buf, buf.len);
}

PyBuffer_Release(&buf);

Py_RETURN_NONE;
Expand DownExpand Up@@ -389,10 +394,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);
Expand Down
33 changes: 17 additions & 16 deletions Modules/_blake2/blake2s_impl.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,7 @@
# define Py_BUILD_CORE_MODULE 1
#endif

#include <stdbool.h>
#include "Python.h"
#include "pycore_strhex.h" // _Py_strhex()

Expand All@@ -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"
Expand All@@ -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;
}
HASHLIB_INIT_MUTEX(self);

return self;
}

Expand DownExpand Up@@ -278,18 +282,19 @@ _blake2_blake2s_update(BLAKE2sObject *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);
blake2s_update(&self->state, buf.buf, buf.len);
PyThread_release_lock(self->lock);
Py_END_ALLOW_THREADS
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);
PyMutex_Unlock(&self->mutex);
Py_END_ALLOW_THREADS
} else {
blake2s_update(&self->state, buf.buf, buf.len);
}

PyBuffer_Release(&buf);

Py_RETURN_NONE;
Expand DownExpand Up@@ -389,10 +394,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);
Expand Down
45 changes: 18 additions & 27 deletions Modules/_hashopenssl.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,7 @@
# define Py_BUILD_CORE_MODULE 1
#endif

#include <stdbool.h>
#include "Python.h"
#include "pycore_hashtable.h"
#include "pycore_pyhash.h" // _Py_HashBytes()
Expand DownExpand Up@@ -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; /* OpenSSL context lock */
} 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; /* HMAC context lock */
} HMACobject;

#include "clinic/_hashopenssl.c.h"
Expand DownExpand Up@@ -414,8 +415,7 @@ newEVPobject(PyTypeObject *type)
if (retval == NULL) {
return NULL;
}

retval->lock = NULL;
HASHLIB_INIT_MUTEX(retval);

retval->ctx = EVP_MD_CTX_new();
if (retval->ctx == NULL) {
Expand DownExpand Up@@ -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);
Expand DownExpand Up@@ -582,16 +580,14 @@ 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->use_mutex && view.len >= HASHLIB_GIL_MINSIZE) {
self->use_mutex = true;
}

if (self->lock != NULL) {
if (self->use_mutex) {
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);
Expand DownExpand Up@@ -1540,7 +1536,7 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
}

self->ctx = ctx;
self->lock = NULL;
HASHLIB_INIT_MUTEX(self);

if ((msg_obj != NULL) && (msg_obj != Py_None)) {
if (!_hmac_update(self, msg_obj))
Expand DownExpand Up@@ -1582,16 +1578,14 @@ _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->use_mutex && view.len >= HASHLIB_GIL_MINSIZE) {
self->use_mutex = true;
}

if (self->lock != NULL) {
if (self->use_mutex) {
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);
Expand DownExpand Up@@ -1633,7 +1627,7 @@ _hashlib_HMAC_copy_impl(HMACobject *self)
return NULL;
}
retval->ctx = ctx;
retval->lock = NULL;
HASHLIB_INIT_MUTEX(retval);

return (PyObject *)retval;
}
Expand All@@ -1642,9 +1636,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);
Expand Down
65 changes: 58 additions & 7 deletions Modules/clinic/md5module.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading