diff options
-rw-r--r-- | Misc/NEWS.d/next/C API/2024-07-04-13-23-27.gh-issue-113601.K3RLqp.rst | 2 | ||||
-rw-r--r-- | Objects/unicodeobject.c | 26 |
2 files changed, 21 insertions, 7 deletions
diff --git a/Misc/NEWS.d/next/C API/2024-07-04-13-23-27.gh-issue-113601.K3RLqp.rst b/Misc/NEWS.d/next/C API/2024-07-04-13-23-27.gh-issue-113601.K3RLqp.rst new file mode 100644 index 00000000000..009cc2bf017 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2024-07-04-13-23-27.gh-issue-113601.K3RLqp.rst @@ -0,0 +1,2 @@ +Removed debug build assertions related to interning strings, which were +falsely triggered by stable ABI extensions. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 815747e1b1e..bee864a615a 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -257,7 +257,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++; } } @@ -691,10 +692,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 @@ -710,11 +715,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(); @@ -1899,7 +1902,8 @@ unicode_write_cstr(PyObject *unicode, Py_ssize_t index, static PyObject* get_latin1_char(Py_UCS1 ch) { - return Py_NewRef(LATIN1(ch)); + PyObject *o = LATIN1(ch); + return o; } static PyObject* @@ -14895,7 +14899,15 @@ intern_static(PyInterpreterState *interp, PyObject *s /* stolen */) assert(s != NULL); assert(_PyUnicode_CHECK(s)); assert(_PyUnicode_STATE(s).statically_allocated); - assert(!PyUnicode_CHECK_INTERNED(s)); + + switch (PyUnicode_CHECK_INTERNED(s)) { + case SSTATE_NOT_INTERNED: + break; + case SSTATE_INTERNED_IMMORTAL_STATIC: + return s; + default: + Py_FatalError("_PyUnicode_InternStatic called on wrong string"); + } #ifdef Py_DEBUG /* We must not add process-global interned string if there's already a @@ -15015,7 +15027,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); |