bpo-40887: Don't use finalized free lists (GH-20700)

In debug mode, ensure that free lists are no longer used after being
finalized. Set numfree to -1 in finalization functions
(eg. _PyList_Fini()), and then check that numfree is not equal to -1
before using a free list (e.g list_dealloc()).
This commit is contained in:
Victor Stinner 2020-06-08 02:14:47 +02:00 committed by GitHub
parent c96a61e816
commit bcb198385d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 88 additions and 3 deletions

View file

@ -116,6 +116,10 @@ PyFloat_FromDouble(double fval)
struct _Py_float_state *state = &interp->float_state;
PyFloatObject *op = state->free_list;
if (op != NULL) {
#ifdef Py_DEBUG
// PyFloat_FromDouble() must not be called after _PyFloat_Fini()
assert(state->numfree != -1);
#endif
state->free_list = (PyFloatObject *) Py_TYPE(op);
state->numfree--;
}
@ -219,6 +223,10 @@ float_dealloc(PyFloatObject *op)
if (PyFloat_CheckExact(op)) {
PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_float_state *state = &interp->float_state;
#ifdef Py_DEBUG
// float_dealloc() must not be called after _PyFloat_Fini()
assert(state->numfree != -1);
#endif
if (state->numfree >= PyFloat_MAXFREELIST) {
PyObject_FREE(op);
return;
@ -1984,10 +1992,11 @@ void
_PyFloat_ClearFreeList(PyThreadState *tstate)
{
struct _Py_float_state *state = &tstate->interp->float_state;
PyFloatObject *f = state->free_list, *next;
for (; f; f = next) {
next = (PyFloatObject*) Py_TYPE(f);
PyFloatObject *f = state->free_list;
while (f != NULL) {
PyFloatObject *next = (PyFloatObject*) Py_TYPE(f);
PyObject_FREE(f);
f = next;
}
state->free_list = NULL;
state->numfree = 0;
@ -1997,6 +2006,10 @@ void
_PyFloat_Fini(PyThreadState *tstate)
{
_PyFloat_ClearFreeList(tstate);
#ifdef Py_DEBUG
struct _Py_float_state *state = &tstate->interp->float_state;
state->numfree = -1;
#endif
}
/* Print summary info about the state of the optimized allocator */