Skip to content

Commit 5d006db

Browse files
committed
codecs.c: fix race condition
1 parent 6540bf3 commit 5d006db

File tree

3 files changed

+26
-21
lines changed

3 files changed

+26
-21
lines changed

Include/internal/pycore_ucnhash.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ typedef struct {
2828

2929
} _PyUnicode_Name_CAPI;
3030

31+
extern _PyUnicode_Name_CAPI *_PyUnicode_GetNameCAPI(void);
32+
3133
#ifdef __cplusplus
3234
}
3335
#endif

Objects/unicodeobject.c

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5724,6 +5724,22 @@ PyUnicode_AsUTF16String(PyObject *unicode)
57245724
return _PyUnicode_EncodeUTF16(unicode, NULL, 0);
57255725
}
57265726

5727+
_PyUnicode_Name_CAPI *_PyUnicode_GetNameCAPI(void)
5728+
{
5729+
PyInterpreterState *interp = _PyInterpreterState_Get();
5730+
_PyUnicode_Name_CAPI *ucnhash_capi;
5731+
5732+
ucnhash_capi = _Py_atomic_load_ptr(&interp->unicode.ucnhash_capi);
5733+
if (ucnhash_capi == NULL) {
5734+
ucnhash_capi = (_PyUnicode_Name_CAPI *)PyCapsule_Import(
5735+
PyUnicodeData_CAPSULE_NAME, 1);
5736+
5737+
// It's fine if we overwite the value here. It's always the same value.
5738+
_Py_atomic_store_ptr(&interp->unicode.ucnhash_capi, ucnhash_capi);
5739+
}
5740+
return ucnhash_capi;
5741+
}
5742+
57275743
/* --- Unicode Escape Codec ----------------------------------------------- */
57285744

57295745
PyObject *
@@ -5739,7 +5755,6 @@ _PyUnicode_DecodeUnicodeEscapeInternal(const char *s,
57395755
PyObject *errorHandler = NULL;
57405756
PyObject *exc = NULL;
57415757
_PyUnicode_Name_CAPI *ucnhash_capi;
5742-
PyInterpreterState *interp = _PyInterpreterState_Get();
57435758

57445759
// so we can remember if we've seen an invalid escape char or not
57455760
*first_invalid_escape = NULL;
@@ -5887,19 +5902,13 @@ _PyUnicode_DecodeUnicodeEscapeInternal(const char *s,
58875902

58885903
/* \N{name} */
58895904
case 'N':
5890-
ucnhash_capi = interp->unicode.ucnhash_capi;
5905+
ucnhash_capi = _PyUnicode_GetNameCAPI();
58915906
if (ucnhash_capi == NULL) {
5892-
/* load the unicode data module */
5893-
ucnhash_capi = (_PyUnicode_Name_CAPI *)PyCapsule_Import(
5894-
PyUnicodeData_CAPSULE_NAME, 1);
5895-
if (ucnhash_capi == NULL) {
5896-
PyErr_SetString(
5897-
PyExc_UnicodeError,
5898-
"\\N escapes not supported (can't load unicodedata module)"
5899-
);
5900-
goto onError;
5901-
}
5902-
interp->unicode.ucnhash_capi = ucnhash_capi;
5907+
PyErr_SetString(
5908+
PyExc_UnicodeError,
5909+
"\\N escapes not supported (can't load unicodedata module)"
5910+
);
5911+
return NULL;
59035912
}
59045913

59055914
message = "malformed \\N character escape";

Python/codecs.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -949,8 +949,6 @@ PyObject *PyCodec_BackslashReplaceErrors(PyObject *exc)
949949
return Py_BuildValue("(Nn)", res, end);
950950
}
951951

952-
static _PyUnicode_Name_CAPI *ucnhash_capi = NULL;
953-
954952
PyObject *PyCodec_NameReplaceErrors(PyObject *exc)
955953
{
956954
if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) {
@@ -971,13 +969,9 @@ PyObject *PyCodec_NameReplaceErrors(PyObject *exc)
971969
return NULL;
972970
if (!(object = PyUnicodeEncodeError_GetObject(exc)))
973971
return NULL;
972+
_PyUnicode_Name_CAPI *ucnhash_capi = _PyUnicode_GetNameCAPI();
974973
if (!ucnhash_capi) {
975-
/* load the unicode data module */
976-
ucnhash_capi = (_PyUnicode_Name_CAPI *)PyCapsule_Import(
977-
PyUnicodeData_CAPSULE_NAME, 1);
978-
if (!ucnhash_capi) {
979-
return NULL;
980-
}
974+
return NULL;
981975
}
982976
for (i = start, ressize = 0; i < end; ++i) {
983977
/* object is guaranteed to be "ready" */

0 commit comments

Comments
 (0)