diff options
author | Victor Stinner <vstinner@python.org> | 2020-07-03 14:59:12 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-03 14:59:12 (GMT) |
commit | 3549ca313a6103a3adb281ef3a849298b7d7f72c (patch) | |
tree | 55f5527d19bf723a8819ff3cb803a6f1829bab4e | |
parent | 91e1bc18bd467a13bceb62e16fbc435b33381c82 (diff) | |
download | cpython-3549ca313a6103a3adb281ef3a849298b7d7f72c.zip cpython-3549ca313a6103a3adb281ef3a849298b7d7f72c.tar.gz cpython-3549ca313a6103a3adb281ef3a849298b7d7f72c.tar.bz2 |
bpo-1635741: Fix unicode_dealloc() for mortal interned string (GH-21270)
When unicode_dealloc() is called on a mortal interned string, the
string reference counter is now reset at zero.
-rw-r--r-- | Objects/unicodeobject.c | 18 |
1 files changed, 14 insertions, 4 deletions
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 37e7fe5..ca68c57 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1943,13 +1943,20 @@ unicode_dealloc(PyObject *unicode) break; case SSTATE_INTERNED_MORTAL: - /* revive dead object temporarily for DelItem */ - Py_SET_REFCNT(unicode, 3); #ifdef INTERNED_STRINGS + /* Revive the dead object temporarily. PyDict_DelItem() removes two + references (key and value) which were ignored by + PyUnicode_InternInPlace(). Use refcnt=3 rather than refcnt=2 + to prevent calling unicode_dealloc() again. Adjust refcnt after + PyDict_DelItem(). */ + assert(Py_REFCNT(unicode) == 0); + Py_SET_REFCNT(unicode, 3); if (PyDict_DelItem(interned, unicode) != 0) { _PyErr_WriteUnraisableMsg("deletion of interned string failed", NULL); } + assert(Py_REFCNT(unicode) == 1); + Py_SET_REFCNT(unicode, 0); #endif break; @@ -15710,8 +15717,9 @@ PyUnicode_InternInPlace(PyObject **p) return; } - /* The two references in interned are not counted by refcnt. - The deallocator will take care of this */ + /* The two references in interned dict (key and value) are not counted by + refcnt. unicode_dealloc() and _PyUnicode_ClearInterned() take care of + this. */ Py_SET_REFCNT(s, Py_REFCNT(s) - 2); _PyUnicode_STATE(s).interned = SSTATE_INTERNED_MORTAL; #endif @@ -15780,6 +15788,8 @@ _PyUnicode_ClearInterned(PyThreadState *tstate) #endif break; case SSTATE_INTERNED_MORTAL: + // Restore the two references (key and value) ignored + // by PyUnicode_InternInPlace(). Py_SET_REFCNT(s, Py_REFCNT(s) + 2); #ifdef INTERNED_STATS mortal_size += PyUnicode_GET_LENGTH(s); |