diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 444f832f5bd8d3..255b31210874ea 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -45,7 +45,10 @@ PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void); typedef struct _Py_Identifier { struct _Py_Identifier *next; const char* string; - PyObject *object; + // bpo-39465: _PyUnicode_FromId() can be called by multiple threads + // running in different interpreters. Use an atomic variable rather + // than a lock for better parallelism. + _Atomic PyObject *object; } _Py_Identifier; #define _Py_static_string_init(value) { .next = NULL, .string = value, .object = NULL } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index ea46a44bf5faac..c8421a3a53e7fa 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -2275,18 +2275,24 @@ PyUnicode_FromString(const char *u) PyObject * _PyUnicode_FromId(_Py_Identifier *id) { - if (!id->object) { - id->object = PyUnicode_DecodeUTF8Stateful(id->string, - strlen(id->string), - NULL, NULL); - if (!id->object) - return NULL; - PyUnicode_InternInPlace(&id->object); - assert(!id->next); - id->next = static_strings; - static_strings = id; + if (id->object) { + return (PyObject *)id->object; } - return id->object; + + PyObject *object; + object = PyUnicode_DecodeUTF8Stateful(id->string, + strlen(id->string), + NULL, NULL); + if (!object) { + return NULL; + } + + PyUnicode_InternInPlace(&object); + id->object = (_Atomic PyObject *)object; + assert(!id->next); + id->next = static_strings; + static_strings = id; + return object; } static void