Skip to content

Commit 3549ca3

Browse files
authored
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.
1 parent 91e1bc1 commit 3549ca3

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

Objects/unicodeobject.c

+14-4
Original file line numberDiff line numberDiff line change
@@ -1943,13 +1943,20 @@ unicode_dealloc(PyObject *unicode)
19431943
break;
19441944

19451945
case SSTATE_INTERNED_MORTAL:
1946-
/* revive dead object temporarily for DelItem */
1947-
Py_SET_REFCNT(unicode, 3);
19481946
#ifdef INTERNED_STRINGS
1947+
/* Revive the dead object temporarily. PyDict_DelItem() removes two
1948+
references (key and value) which were ignored by
1949+
PyUnicode_InternInPlace(). Use refcnt=3 rather than refcnt=2
1950+
to prevent calling unicode_dealloc() again. Adjust refcnt after
1951+
PyDict_DelItem(). */
1952+
assert(Py_REFCNT(unicode) == 0);
1953+
Py_SET_REFCNT(unicode, 3);
19491954
if (PyDict_DelItem(interned, unicode) != 0) {
19501955
_PyErr_WriteUnraisableMsg("deletion of interned string failed",
19511956
NULL);
19521957
}
1958+
assert(Py_REFCNT(unicode) == 1);
1959+
Py_SET_REFCNT(unicode, 0);
19531960
#endif
19541961
break;
19551962

@@ -15710,8 +15717,9 @@ PyUnicode_InternInPlace(PyObject **p)
1571015717
return;
1571115718
}
1571215719

15713-
/* The two references in interned are not counted by refcnt.
15714-
The deallocator will take care of this */
15720+
/* The two references in interned dict (key and value) are not counted by
15721+
refcnt. unicode_dealloc() and _PyUnicode_ClearInterned() take care of
15722+
this. */
1571515723
Py_SET_REFCNT(s, Py_REFCNT(s) - 2);
1571615724
_PyUnicode_STATE(s).interned = SSTATE_INTERNED_MORTAL;
1571715725
#endif
@@ -15780,6 +15788,8 @@ _PyUnicode_ClearInterned(PyThreadState *tstate)
1578015788
#endif
1578115789
break;
1578215790
case SSTATE_INTERNED_MORTAL:
15791+
// Restore the two references (key and value) ignored
15792+
// by PyUnicode_InternInPlace().
1578315793
Py_SET_REFCNT(s, Py_REFCNT(s) + 2);
1578415794
#ifdef INTERNED_STATS
1578515795
mortal_size += PyUnicode_GET_LENGTH(s);

0 commit comments

Comments
 (0)