diff options
| author | Victor Stinner <vstinner@python.org> | 2020-07-03 16:59:12 +0200 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-07-03 16:59:12 +0200 | 
| commit | 3549ca313a6103a3adb281ef3a849298b7d7f72c (patch) | |
| tree | 55f5527d19bf723a8819ff3cb803a6f1829bab4e | |
| parent | 91e1bc18bd467a13bceb62e16fbc435b33381c82 (diff) | |
| download | cpython-git-3549ca313a6103a3adb281ef3a849298b7d7f72c.tar.gz | |
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 37e7fe5c0e..ca68c57534 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);  | 
