Skip to content

Commit ec3c99c

Browse files
authored
bpo-38631: Avoid Py_FatalError() in unicodeobject.c (GH-18281)
Replace Py_FatalError() calls with _PyErr_WriteUnraisableMsg(), _PyObject_ASSERT_FAILED_MSG() or Py_UNREACHABLE() in unicode_dealloc() and unicode_release_interned().
1 parent 38c878b commit ec3c99c

File tree

1 file changed

+28
-23
lines changed

1 file changed

+28
-23
lines changed

Objects/unicodeobject.c

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,25 +1900,29 @@ unicode_dealloc(PyObject *unicode)
19001900
case SSTATE_INTERNED_MORTAL:
19011901
/* revive dead object temporarily for DelItem */
19021902
Py_REFCNT(unicode) = 3;
1903-
if (PyDict_DelItem(interned, unicode) != 0)
1904-
Py_FatalError(
1905-
"deletion of interned string failed");
1903+
if (PyDict_DelItem(interned, unicode) != 0) {
1904+
_PyErr_WriteUnraisableMsg("deletion of interned string failed",
1905+
NULL);
1906+
}
19061907
break;
19071908

19081909
case SSTATE_INTERNED_IMMORTAL:
1909-
Py_FatalError("Immortal interned string died.");
1910-
/* fall through */
1910+
_PyObject_ASSERT_FAILED_MSG(unicode, "Immortal interned string died");
1911+
break;
19111912

19121913
default:
1913-
Py_FatalError("Inconsistent interned string state.");
1914+
Py_UNREACHABLE();
19141915
}
19151916

1916-
if (_PyUnicode_HAS_WSTR_MEMORY(unicode))
1917+
if (_PyUnicode_HAS_WSTR_MEMORY(unicode)) {
19171918
PyObject_DEL(_PyUnicode_WSTR(unicode));
1918-
if (_PyUnicode_HAS_UTF8_MEMORY(unicode))
1919+
}
1920+
if (_PyUnicode_HAS_UTF8_MEMORY(unicode)) {
19191921
PyObject_DEL(_PyUnicode_UTF8(unicode));
1920-
if (!PyUnicode_IS_COMPACT(unicode) && _PyUnicode_DATA_ANY(unicode))
1922+
}
1923+
if (!PyUnicode_IS_COMPACT(unicode) && _PyUnicode_DATA_ANY(unicode)) {
19211924
PyObject_DEL(_PyUnicode_DATA_ANY(unicode));
1925+
}
19221926

19231927
Py_TYPE(unicode)->tp_free(unicode);
19241928
}
@@ -15401,14 +15405,10 @@ PyUnicode_InternFromString(const char *cp)
1540115405
static void
1540215406
unicode_release_interned(void)
1540315407
{
15404-
PyObject *keys;
15405-
PyObject *s;
15406-
Py_ssize_t i, n;
15407-
Py_ssize_t immortal_size = 0, mortal_size = 0;
15408-
15409-
if (interned == NULL || !PyDict_Check(interned))
15408+
if (interned == NULL || !PyDict_Check(interned)) {
1541015409
return;
15411-
keys = PyDict_Keys(interned);
15410+
}
15411+
PyObject *keys = PyDict_Keys(interned);
1541215412
if (keys == NULL || !PyList_Check(keys)) {
1541315413
PyErr_Clear();
1541415414
return;
@@ -15419,30 +15419,35 @@ unicode_release_interned(void)
1541915419
rather, we give them their stolen references back, and then clear
1542015420
and DECREF the interned dict. */
1542115421

15422-
n = PyList_GET_SIZE(keys);
15422+
Py_ssize_t n = PyList_GET_SIZE(keys);
1542315423
#ifdef INTERNED_STATS
1542415424
fprintf(stderr, "releasing %" PY_FORMAT_SIZE_T "d interned strings\n",
1542515425
n);
15426+
15427+
Py_ssize_t immortal_size = 0, mortal_size = 0;
1542615428
#endif
15427-
for (i = 0; i < n; i++) {
15428-
s = PyList_GET_ITEM(keys, i);
15429+
for (Py_ssize_t i = 0; i < n; i++) {
15430+
PyObject *s = PyList_GET_ITEM(keys, i);
1542915431
if (PyUnicode_READY(s) == -1) {
1543015432
Py_UNREACHABLE();
1543115433
}
1543215434
switch (PyUnicode_CHECK_INTERNED(s)) {
15433-
case SSTATE_NOT_INTERNED:
15434-
/* XXX Shouldn't happen */
15435-
break;
1543615435
case SSTATE_INTERNED_IMMORTAL:
1543715436
Py_REFCNT(s) += 1;
15437+
#ifdef INTERNED_STATS
1543815438
immortal_size += PyUnicode_GET_LENGTH(s);
15439+
#endif
1543915440
break;
1544015441
case SSTATE_INTERNED_MORTAL:
1544115442
Py_REFCNT(s) += 2;
15443+
#ifdef INTERNED_STATS
1544215444
mortal_size += PyUnicode_GET_LENGTH(s);
15445+
#endif
1544315446
break;
15447+
case SSTATE_NOT_INTERNED:
15448+
/* fall through */
1544415449
default:
15445-
Py_FatalError("Inconsistent interned string state.");
15450+
Py_UNREACHABLE();
1544615451
}
1544715452
_PyUnicode_STATE(s).interned = SSTATE_NOT_INTERNED;
1544815453
}

0 commit comments

Comments
 (0)