Skip to content

Commit

Permalink
codecs.c: fix race condition
Browse files Browse the repository at this point in the history
  • Loading branch information
colesbury committed Apr 23, 2023
1 parent 6540bf3 commit 5d006db
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 21 deletions.
2 changes: 2 additions & 0 deletions Include/internal/pycore_ucnhash.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ typedef struct {

} _PyUnicode_Name_CAPI;

extern _PyUnicode_Name_CAPI *_PyUnicode_GetNameCAPI(void);

#ifdef __cplusplus
}
#endif
Expand Down
35 changes: 22 additions & 13 deletions Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -5724,6 +5724,22 @@ 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 *
Expand All @@ -5739,7 +5755,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;
Expand Down Expand Up @@ -5887,19 +5902,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(
PyExc_UnicodeError,
"\\N escapes not supported (can't load unicodedata module)"
);
goto onError;
}
interp->unicode.ucnhash_capi = ucnhash_capi;
PyErr_SetString(
PyExc_UnicodeError,
"\\N escapes not supported (can't load unicodedata module)"
);
return NULL;
}

message = "malformed \\N character escape";
Expand Down
10 changes: 2 additions & 8 deletions Python/codecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -949,8 +949,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)) {
Expand All @@ -971,13 +969,9 @@ PyObject *PyCodec_NameReplaceErrors(PyObject *exc)
return NULL;
if (!(object = PyUnicodeEncodeError_GetObject(exc)))
return NULL;
_PyUnicode_Name_CAPI *ucnhash_capi = _PyUnicode_GetNameCAPI();
if (!ucnhash_capi) {
/* load the unicode data module */
ucnhash_capi = (_PyUnicode_Name_CAPI *)PyCapsule_Import(
PyUnicodeData_CAPSULE_NAME, 1);
if (!ucnhash_capi) {
return NULL;
}
return NULL;
}
for (i = start, ressize = 0; i < end; ++i) {
/* object is guaranteed to be "ready" */
Expand Down

0 comments on commit 5d006db

Please sign in to comment.