From bc2dac3f374e74a8ecc5c93d30bfb02d705e7370 Mon Sep 17 00:00:00 2001 From: Radislav Chugunov Date: Wed, 15 Nov 2023 02:32:16 +0300 Subject: [PATCH] gh-112062: Make `_struct` module thread-safe in --disable-gil builds * use `PyDict_GetItemRef` instead of `PyDict_GetItemWithError` in `cache_struct_converter` to avoid usage of borrowed ref with explicit incref * clear cache dict but preserve the reference in `_clearcache_impl` * create cache dict in `_structmodule_exec` --- Modules/_struct.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/Modules/_struct.c b/Modules/_struct.c index ff1bf4e96c5f21..9d5fa6026dace2 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -2250,20 +2250,12 @@ cache_struct_converter(PyObject *module, PyObject *fmt, PyStructObject **ptr) return 1; } - if (state->cache == NULL) { - state->cache = PyDict_New(); - if (state->cache == NULL) - return 0; + if (PyDict_GetItemRef(state->cache, fmt, ptr) < 0) { + return 0; } - - s_object = PyDict_GetItemWithError(state->cache, fmt); - if (s_object != NULL) { - *ptr = (PyStructObject *)Py_NewRef(s_object); + if (*ptr != NULL) { return Py_CLEANUP_SUPPORTED; } - else if (PyErr_Occurred()) { - return 0; - } s_object = PyObject_CallOneArg(state->PyStructType, fmt); if (s_object != NULL) { @@ -2288,7 +2280,7 @@ static PyObject * _clearcache_impl(PyObject *module) /*[clinic end generated code: output=ce4fb8a7bf7cb523 input=463eaae04bab3211]*/ { - Py_CLEAR(get_struct_state(module)->cache); + PyDict_Clear(get_struct_state(module)->cache); Py_RETURN_NONE; } @@ -2512,6 +2504,11 @@ _structmodule_exec(PyObject *m) { _structmodulestate *state = get_struct_state(m); + state->cache = PyDict_New(); + if (state->cache == NULL) { + return -1; + } + state->PyStructType = PyType_FromModuleAndSpec( m, &PyStructType_spec, NULL); if (state->PyStructType == NULL) {