"(can't load unicodedata module)"
self.assertIn(error, result.err.decode("ascii"))
+ def test_unicodedata_unload_reload(self):
+ # gh-149449: dropping unicodedata and running gc must not leave the
+ # cached _ucnhash_CAPI pointer dangling.
+ code = (
+ "import gc, sys\n"
+ "assert '\\N{GRINNING FACE}'.encode("
+ " 'ascii', errors='namereplace') == b'\\\\N{GRINNING FACE}'\n"
+ "compile(r\"x = '\\\\N{LATIN CAPITAL LETTER A}'\", '<x>', 'exec')\n"
+ "del sys.modules['unicodedata']\n"
+ "gc.collect()\n"
+ "assert '\\N{WINKING FACE}'.encode("
+ " 'ascii', errors='namereplace') == b'\\\\N{WINKING FACE}'\n"
+ "compile(r\"x = '\\\\N{LATIN CAPITAL LETTER B}'\", '<x>', 'exec')\n"
+ )
+ script_helper.assert_python_ok("-c", code)
+
def test_decimal_numeric_consistent(self):
# Test that decimal and numeric are consistent,
# i.e. if a character has a decimal value,
--- /dev/null
+Fix a use-after-free crash when the :mod:`unicodedata` module was removed
+from :data:`sys.modules` and garbage-collected between calls that decode
+``\N{...}`` escapes or use the ``namereplace`` codec error handler.
return _check_alias_and_seq(code, with_named_seq);
}
-static void
-unicodedata_destroy_capi(PyObject *capsule)
-{
- void *capi = PyCapsule_GetPointer(capsule, PyUnicodeData_CAPSULE_NAME);
- PyMem_Free(capi);
-}
-
static PyObject *
unicodedata_create_capi(void)
{
- _PyUnicode_Name_CAPI *capi = PyMem_Malloc(sizeof(_PyUnicode_Name_CAPI));
- if (capi == NULL) {
- PyErr_NoMemory();
- return NULL;
- }
- capi->getname = capi_getucname;
- capi->getcode = capi_getcode;
-
- PyObject *capsule = PyCapsule_New(capi,
- PyUnicodeData_CAPSULE_NAME,
- unicodedata_destroy_capi);
- if (capsule == NULL) {
- PyMem_Free(capi);
- }
- return capsule;
-};
+ // Statically allocated so that any cached pointers stay valid after unicodedata
+ // is removed from sys.modules and the capsule is gc'd (gh-149449).
+ static _PyUnicode_Name_CAPI capi = {
+ .getname = capi_getucname,
+ .getcode = capi_getcode,
+ };
+ return PyCapsule_New(&capi, PyUnicodeData_CAPSULE_NAME, NULL);
+}
/* -------------------------------------------------------------------- */
Modules/pyexpat.c - handler_info -
Modules/termios.c - termios_constants -
Modules/timemodule.c init_timezone YEAR -
+Modules/unicodedata.c unicodedata_create_capi capi -
Objects/bytearrayobject.c - _PyByteArray_empty_string -
Objects/complexobject.c - c_1 -
Objects/exceptions.c - static_exceptions -