Skip to content
53 changes: 17 additions & 36 deletions Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -15657,52 +15657,46 @@ PyUnicode_InternFromString(const char *cp)
}


#if defined(WITH_VALGRIND) || defined(__INSURE__)
static void
unicode_release_interned(void)
{
Py_ssize_t pos = 0;
PyObject *s, *ignored_value;

if (interned == NULL || !PyDict_Check(interned)) {
return;
}
PyObject *keys = PyDict_Keys(interned);
if (keys == NULL || !PyList_Check(keys)) {
PyErr_Clear();
return;
}

/* Since unicode_release_interned() is intended to help a leak
detector, interned unicode strings are not forcibly deallocated;
rather, we give them their stolen references back, and then clear
and DECREF the interned dict. */

Py_ssize_t n = PyList_GET_SIZE(keys);
#ifdef INTERNED_STATS
fprintf(stderr, "releasing %zd interned strings\n", n);
fprintf(stderr, "releasing %zd interned strings\n", PyDict_Size(interned));

Py_ssize_t immortal_size = 0, mortal_size = 0;
#endif
for (Py_ssize_t i = 0; i < n; i++) {
PyObject *s = PyList_GET_ITEM(keys, i);
while (PyDict_Next(interned, &pos, &s, &ignored_value)) {
if (PyUnicode_READY(s) == -1) {
Py_UNREACHABLE();
}
switch (PyUnicode_CHECK_INTERNED(s)) {
case SSTATE_INTERNED_IMMORTAL:
Py_SET_REFCNT(s, Py_REFCNT(s) + 1);
case SSTATE_INTERNED_IMMORTAL:
Py_SET_REFCNT(s, Py_REFCNT(s) + 1);
#ifdef INTERNED_STATS
immortal_size += PyUnicode_GET_LENGTH(s);
immortal_size += PyUnicode_GET_LENGTH(s);
#endif
break;
case SSTATE_INTERNED_MORTAL:
Py_SET_REFCNT(s, Py_REFCNT(s) + 2);
break;
case SSTATE_INTERNED_MORTAL:
Py_SET_REFCNT(s, Py_REFCNT(s) + 2);
#ifdef INTERNED_STATS
mortal_size += PyUnicode_GET_LENGTH(s);
mortal_size += PyUnicode_GET_LENGTH(s);
#endif
break;
case SSTATE_NOT_INTERNED:
/* fall through */
default:
Py_UNREACHABLE();
break;
case SSTATE_NOT_INTERNED:
/* fall through */
default:
Py_UNREACHABLE();
}
_PyUnicode_STATE(s).interned = SSTATE_NOT_INTERNED;
}
Expand All @@ -15711,11 +15705,9 @@ unicode_release_interned(void)
"total size of all interned strings: %zd/%zd mortal/immortal\n",
mortal_size, immortal_size);
#endif
Py_DECREF(keys);
PyDict_Clear(interned);
Py_CLEAR(interned);
}
#endif


/********************* Unicode Iterator **************************/
Expand Down Expand Up @@ -16209,18 +16201,7 @@ _PyUnicode_Fini(PyThreadState *tstate)

int is_main_interp = _Py_IsMainInterpreter(tstate);
if (is_main_interp) {
#if defined(WITH_VALGRIND) || defined(__INSURE__)
/* Insure++ is a memory analysis tool that aids in discovering
* memory leaks and other memory problems. On Python exit, the
* interned string dictionaries are flagged as being in use at exit
* (which it is). Under normal circumstances, this is fine because
* the memory will be automatically reclaimed by the system. Under
* memory debugging, it's a huge source of useless noise, so we
* trade off slower shutdown for less distraction in the memory
* reports. -baw
*/
unicode_release_interned();
#endif /* __INSURE__ */
}

Py_CLEAR(state->empty);
Expand Down
4 changes: 2 additions & 2 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -1259,14 +1259,14 @@ finalize_interp_types(PyThreadState *tstate, int is_main_interp)
_PyAsyncGen_Fini(tstate);
_PyContext_Fini(tstate);

_PyDict_Fini(tstate);
_PyList_Fini(tstate);
_PyUnicode_Fini(tstate);
_PyDict_Fini(tstate);
_PyTuple_Fini(tstate);

_PySlice_Fini(tstate);

_PyBytes_Fini(tstate);
_PyUnicode_Fini(tstate);
_PyFloat_Fini(tstate);
_PyLong_Fini(tstate);
}
Expand Down