Skip to content

Commit

Permalink
pythongh-113993: For string interning, do not rely on (or assert) _Py…
Browse files Browse the repository at this point in the history
…_IsImmortal (pythonGH-121358)

Older stable ABI extensions are allowed to make immortal objects mortal.
Instead, use `_PyUnicode_STATE` (`interned` and `statically_allocated`).
  • Loading branch information
encukou committed Jul 16, 2024
1 parent a0b205b commit 956270d
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Removed debug build assertions related to interning strings, which were
falsely triggered by stable ABI extensions.
15 changes: 8 additions & 7 deletions Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ _PyUnicode_InternedSize_Immortal(void)
// value, to help detect bugs in optimizations.

while (PyDict_Next(dict, &pos, &key, &value)) {
if (_Py_IsImmortal(key)) {
assert(PyUnicode_CHECK_INTERNED(key) != SSTATE_INTERNED_IMMORTAL_STATIC);
if (PyUnicode_CHECK_INTERNED(key) == SSTATE_INTERNED_IMMORTAL) {
count++;
}
}
Expand Down Expand Up @@ -688,10 +689,14 @@ _PyUnicode_CheckConsistency(PyObject *op, int check_content)

/* Check interning state */
#ifdef Py_DEBUG
// Note that we do not check `_Py_IsImmortal(op)`, since stable ABI
// extensions can make immortal strings mortal (but with a high enough
// refcount).
// The other way is extremely unlikely (worth a potential failed assertion
// in a debug build), so we do check `!_Py_IsImmortal(op)`.
switch (PyUnicode_CHECK_INTERNED(op)) {
case SSTATE_NOT_INTERNED:
if (ascii->state.statically_allocated) {
CHECK(_Py_IsImmortal(op));
// This state is for two exceptions:
// - strings are currently checked before they're interned
// - the 256 one-latin1-character strings
Expand All @@ -707,11 +712,9 @@ _PyUnicode_CheckConsistency(PyObject *op, int check_content)
break;
case SSTATE_INTERNED_IMMORTAL:
CHECK(!ascii->state.statically_allocated);
CHECK(_Py_IsImmortal(op));
break;
case SSTATE_INTERNED_IMMORTAL_STATIC:
CHECK(ascii->state.statically_allocated);
CHECK(_Py_IsImmortal(op));
break;
default:
Py_UNREACHABLE();
Expand Down Expand Up @@ -1867,7 +1870,6 @@ static PyObject*
get_latin1_char(Py_UCS1 ch)
{
PyObject *o = LATIN1(ch);
assert(_Py_IsImmortal(o));
return o;
}

Expand Down Expand Up @@ -15352,7 +15354,6 @@ intern_static(PyInterpreterState *interp, PyObject *s /* stolen */)
assert(s != NULL);
assert(_PyUnicode_CHECK(s));
assert(_PyUnicode_STATE(s).statically_allocated);
assert(_Py_IsImmortal(s));

switch (PyUnicode_CHECK_INTERNED(s)) {
case SSTATE_NOT_INTERNED:
Expand Down Expand Up @@ -15493,7 +15494,7 @@ intern_common(PyInterpreterState *interp, PyObject *s /* stolen */,
{
PyObject *r = (PyObject *)_Py_hashtable_get(INTERNED_STRINGS, s);
if (r != NULL) {
assert(_Py_IsImmortal(r));
assert(_PyUnicode_STATE(r).statically_allocated);
assert(r != s); // r must be statically_allocated; s is not
Py_DECREF(s);
return Py_NewRef(r);
Expand Down

0 comments on commit 956270d

Please sign in to comment.