]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-111972: Make Unicode name C APIcapsule initialization thread-safe (#112249)
authorKirill Podoprigora <kirill.bast9@mail.ru>
Thu, 30 Nov 2023 10:12:49 +0000 (13:12 +0300)
committerGitHub <noreply@github.com>
Thu, 30 Nov 2023 10:12:49 +0000 (11:12 +0100)
Include/internal/pycore_ucnhash.h
Objects/unicodeobject.c
Python/codecs.c

index 187dd68e7347ff3fc90371de01d367dc9b5f0338..1561dfbb3150d3fe3d61898c51701ef2831e8e2f 100644 (file)
@@ -28,6 +28,8 @@ typedef struct {
 
 } _PyUnicode_Name_CAPI;
 
+extern _PyUnicode_Name_CAPI* _PyUnicode_GetNameCAPI(void);
+
 #ifdef __cplusplus
 }
 #endif
index cffc06297a9aeea245d69604132e9d74a842f37d..10022e23c04abf9d02b9786bff626ebbb65ebf33 100644 (file)
@@ -5869,6 +5869,23 @@ PyUnicode_AsUTF16String(PyObject *unicode)
     return _PyUnicode_EncodeUTF16(unicode, NULL, 0);
 }
 
+_PyUnicode_Name_CAPI *
+_PyUnicode_GetNameCAPI(void)
+{
+    PyInterpreterState *interp = _PyInterpreterState_GET();
+    _PyUnicode_Name_CAPI *ucnhash_capi;
+
+    ucnhash_capi = _Py_atomic_load_ptr(&interp->unicode.ucnhash_capi);
+    if (ucnhash_capi == NULL) {
+        ucnhash_capi = (_PyUnicode_Name_CAPI *)PyCapsule_Import(
+                PyUnicodeData_CAPSULE_NAME, 1);
+
+        // It's fine if we overwite the value here. It's always the same value.
+        _Py_atomic_store_ptr(&interp->unicode.ucnhash_capi, ucnhash_capi);
+    }
+    return ucnhash_capi;
+}
+
 /* --- Unicode Escape Codec ----------------------------------------------- */
 
 PyObject *
@@ -5884,7 +5901,6 @@ _PyUnicode_DecodeUnicodeEscapeInternal(const char *s,
     PyObject *errorHandler = NULL;
     PyObject *exc = NULL;
     _PyUnicode_Name_CAPI *ucnhash_capi;
-    PyInterpreterState *interp = _PyInterpreterState_GET();
 
     // so we can remember if we've seen an invalid escape char or not
     *first_invalid_escape = NULL;
@@ -6032,19 +6048,13 @@ _PyUnicode_DecodeUnicodeEscapeInternal(const char *s,
 
             /* \N{name} */
         case 'N':
-            ucnhash_capi = interp->unicode.ucnhash_capi;
+            ucnhash_capi = _PyUnicode_GetNameCAPI();
             if (ucnhash_capi == NULL) {
-                /* load the unicode data module */
-                ucnhash_capi = (_PyUnicode_Name_CAPI *)PyCapsule_Import(
-                                                PyUnicodeData_CAPSULE_NAME, 1);
-                if (ucnhash_capi == NULL) {
-                    PyErr_SetString(
+                PyErr_SetString(
                         PyExc_UnicodeError,
                         "\\N escapes not supported (can't load unicodedata module)"
-                        );
-                    goto onError;
-                }
-                interp->unicode.ucnhash_capi = ucnhash_capi;
+                );
+                goto onError;
             }
 
             message = "malformed \\N character escape";
index 545bf82e00dca1d4c1c6230d4946ae19c1c80c86..d8fe7b22063a809cfb44ca99c4977f0d1e6c4a6f 100644 (file)
@@ -931,8 +931,6 @@ PyObject *PyCodec_BackslashReplaceErrors(PyObject *exc)
     return Py_BuildValue("(Nn)", res, end);
 }
 
-static _PyUnicode_Name_CAPI *ucnhash_capi = NULL;
-
 PyObject *PyCodec_NameReplaceErrors(PyObject *exc)
 {
     if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) {
@@ -953,13 +951,9 @@ PyObject *PyCodec_NameReplaceErrors(PyObject *exc)
             return NULL;
         if (!(object = PyUnicodeEncodeError_GetObject(exc)))
             return NULL;
-        if (!ucnhash_capi) {
-            /* load the unicode data module */
-            ucnhash_capi = (_PyUnicode_Name_CAPI *)PyCapsule_Import(
-                                            PyUnicodeData_CAPSULE_NAME, 1);
-            if (!ucnhash_capi) {
-                return NULL;
-            }
+        _PyUnicode_Name_CAPI *ucnhash_capi = _PyUnicode_GetNameCAPI();
+        if (ucnhash_capi == NULL) {
+            return NULL;
         }
         for (i = start, ressize = 0; i < end; ++i) {
             /* object is guaranteed to be "ready" */