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; struct _Py_float_state *state = &interp->float_state;
PyFloatObject *op = state->free_list; PyFloatObject *op = state->free_list;
if (op != NULL) { 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->free_list = (PyFloatObject *) Py_TYPE(op);
state->numfree--; state->numfree--;
} }
@ -219,6 +223,10 @@ float_dealloc(PyFloatObject *op)
if (PyFloat_CheckExact(op)) { if (PyFloat_CheckExact(op)) {
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_float_state *state = &interp->float_state; 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) { if (state->numfree >= PyFloat_MAXFREELIST) {
PyObject_FREE(op); PyObject_FREE(op);
return; return;
@ -1984,10 +1992,11 @@ void
_PyFloat_ClearFreeList(PyThreadState *tstate) _PyFloat_ClearFreeList(PyThreadState *tstate)
{ {
struct _Py_float_state *state = &tstate->interp->float_state; struct _Py_float_state *state = &tstate->interp->float_state;
PyFloatObject *f = state->free_list, *next; PyFloatObject *f = state->free_list;
for (; f; f = next) { while (f != NULL) {
next = (PyFloatObject*) Py_TYPE(f); PyFloatObject *next = (PyFloatObject*) Py_TYPE(f);
PyObject_FREE(f); PyObject_FREE(f);
f = next;
} }
state->free_list = NULL; state->free_list = NULL;
state->numfree = 0; state->numfree = 0;
@ -1997,6 +2006,10 @@ void
_PyFloat_Fini(PyThreadState *tstate) _PyFloat_Fini(PyThreadState *tstate)
{ {
_PyFloat_ClearFreeList(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 */ /* Print summary info about the state of the optimized allocator */

View File

@ -595,6 +595,10 @@ frame_dealloc(PyFrameObject *f)
else { else {
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_frame_state *state = &interp->frame; struct _Py_frame_state *state = &interp->frame;
#ifdef Py_DEBUG
// frame_dealloc() must not be called after _PyFrame_Fini()
assert(state->numfree != -1);
#endif
if (state->numfree < PyFrame_MAXFREELIST) { if (state->numfree < PyFrame_MAXFREELIST) {
++state->numfree; ++state->numfree;
f->f_back = state->free_list; f->f_back = state->free_list;
@ -790,6 +794,10 @@ frame_alloc(PyCodeObject *code)
} }
} }
else { else {
#ifdef Py_DEBUG
// frame_alloc() must not be called after _PyFrame_Fini()
assert(state->numfree != -1);
#endif
assert(state->numfree > 0); assert(state->numfree > 0);
--state->numfree; --state->numfree;
f = state->free_list; f = state->free_list;
@ -1188,6 +1196,10 @@ void
_PyFrame_Fini(PyThreadState *tstate) _PyFrame_Fini(PyThreadState *tstate)
{ {
_PyFrame_ClearFreeList(tstate); _PyFrame_ClearFreeList(tstate);
#ifdef Py_DEBUG
struct _Py_frame_state *state = &tstate->interp->frame;
state->numfree = -1;
#endif
} }
/* Print summary info about the state of the optimized allocator */ /* Print summary info about the state of the optimized allocator */

View File

@ -1430,6 +1430,11 @@ void
_PyAsyncGen_Fini(PyThreadState *tstate) _PyAsyncGen_Fini(PyThreadState *tstate)
{ {
_PyAsyncGen_ClearFreeLists(tstate); _PyAsyncGen_ClearFreeLists(tstate);
#ifdef Py_DEBUG
struct _Py_async_gen_state *state = &tstate->interp->async_gen;
state->value_numfree = -1;
state->asend_numfree = -1;
#endif
} }
@ -1474,6 +1479,10 @@ async_gen_asend_dealloc(PyAsyncGenASend *o)
Py_CLEAR(o->ags_sendval); Py_CLEAR(o->ags_sendval);
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_async_gen_state *state = &interp->async_gen; struct _Py_async_gen_state *state = &interp->async_gen;
#ifdef Py_DEBUG
// async_gen_asend_dealloc() must not be called after _PyAsyncGen_Fini()
assert(state->asend_numfree != -1);
#endif
if (state->asend_numfree < _PyAsyncGen_MAXFREELIST) { if (state->asend_numfree < _PyAsyncGen_MAXFREELIST) {
assert(PyAsyncGenASend_CheckExact(o)); assert(PyAsyncGenASend_CheckExact(o));
state->asend_freelist[state->asend_numfree++] = o; state->asend_freelist[state->asend_numfree++] = o;
@ -1632,6 +1641,10 @@ async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval)
PyAsyncGenASend *o; PyAsyncGenASend *o;
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_async_gen_state *state = &interp->async_gen; struct _Py_async_gen_state *state = &interp->async_gen;
#ifdef Py_DEBUG
// async_gen_asend_new() must not be called after _PyAsyncGen_Fini()
assert(state->asend_numfree != -1);
#endif
if (state->asend_numfree) { if (state->asend_numfree) {
state->asend_numfree--; state->asend_numfree--;
o = state->asend_freelist[state->asend_numfree]; o = state->asend_freelist[state->asend_numfree];
@ -1667,6 +1680,10 @@ async_gen_wrapped_val_dealloc(_PyAsyncGenWrappedValue *o)
Py_CLEAR(o->agw_val); Py_CLEAR(o->agw_val);
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_async_gen_state *state = &interp->async_gen; struct _Py_async_gen_state *state = &interp->async_gen;
#ifdef Py_DEBUG
// async_gen_wrapped_val_dealloc() must not be called after _PyAsyncGen_Fini()
assert(state->value_numfree != -1);
#endif
if (state->value_numfree < _PyAsyncGen_MAXFREELIST) { if (state->value_numfree < _PyAsyncGen_MAXFREELIST) {
assert(_PyAsyncGenWrappedValue_CheckExact(o)); assert(_PyAsyncGenWrappedValue_CheckExact(o));
state->value_freelist[state->value_numfree++] = o; state->value_freelist[state->value_numfree++] = o;
@ -1737,6 +1754,10 @@ _PyAsyncGenValueWrapperNew(PyObject *val)
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_async_gen_state *state = &interp->async_gen; struct _Py_async_gen_state *state = &interp->async_gen;
#ifdef Py_DEBUG
// _PyAsyncGenValueWrapperNew() must not be called after _PyAsyncGen_Fini()
assert(state->value_numfree != -1);
#endif
if (state->value_numfree) { if (state->value_numfree) {
state->value_numfree--; state->value_numfree--;
o = state->value_freelist[state->value_numfree]; o = state->value_freelist[state->value_numfree];

View File

@ -111,6 +111,10 @@ void
_PyList_Fini(PyThreadState *tstate) _PyList_Fini(PyThreadState *tstate)
{ {
_PyList_ClearFreeList(tstate); _PyList_ClearFreeList(tstate);
#ifdef Py_DEBUG
struct _Py_list_state *state = &tstate->interp->list;
state->numfree = -1;
#endif
} }
/* Print summary info about the state of the optimized allocator */ /* Print summary info about the state of the optimized allocator */
@ -135,6 +139,10 @@ PyList_New(Py_ssize_t size)
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_list_state *state = &interp->list; struct _Py_list_state *state = &interp->list;
PyListObject *op; PyListObject *op;
#ifdef Py_DEBUG
// PyList_New() must not be called after _PyList_Fini()
assert(state->numfree != -1);
#endif
if (state->numfree) { if (state->numfree) {
state->numfree--; state->numfree--;
op = state->free_list[state->numfree]; op = state->free_list[state->numfree];
@ -330,6 +338,10 @@ list_dealloc(PyListObject *op)
} }
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_list_state *state = &interp->list; struct _Py_list_state *state = &interp->list;
#ifdef Py_DEBUG
// list_dealloc() must not be called after _PyList_Fini()
assert(state->numfree != -1);
#endif
if (state->numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) { if (state->numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) {
state->free_list[state->numfree++] = op; state->free_list[state->numfree++] = op;
} }

View File

@ -54,6 +54,10 @@ tuple_alloc(struct _Py_tuple_state *state, Py_ssize_t size)
return NULL; return NULL;
} }
#if PyTuple_MAXSAVESIZE > 0 #if PyTuple_MAXSAVESIZE > 0
#ifdef Py_DEBUG
// tuple_alloc() must not be called after _PyTuple_Fini()
assert(state->numfree[0] != -1);
#endif
if (size < PyTuple_MAXSAVESIZE && (op = state->free_list[size]) != NULL) { if (size < PyTuple_MAXSAVESIZE && (op = state->free_list[size]) != NULL) {
assert(size != 0); assert(size != 0);
state->free_list[size] = (PyTupleObject *) op->ob_item[0]; state->free_list[size] = (PyTupleObject *) op->ob_item[0];
@ -102,6 +106,10 @@ PyTuple_New(Py_ssize_t size)
} }
#if PyTuple_MAXSAVESIZE > 0 #if PyTuple_MAXSAVESIZE > 0
if (size == 0) { if (size == 0) {
#ifdef Py_DEBUG
// PyTuple_New() must not be called after _PyTuple_Fini()
assert(state->numfree[0] != -1);
#endif
state->free_list[0] = op; state->free_list[0] = op;
++state->numfree[0]; ++state->numfree[0];
Py_INCREF(op); /* extra INCREF so that this is never freed */ Py_INCREF(op); /* extra INCREF so that this is never freed */
@ -227,6 +235,10 @@ tupledealloc(PyTupleObject *op)
#if PyTuple_MAXSAVESIZE > 0 #if PyTuple_MAXSAVESIZE > 0
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_tuple_state *state = &interp->tuple; struct _Py_tuple_state *state = &interp->tuple;
#ifdef Py_DEBUG
// tupledealloc() must not be called after _PyTuple_Fini()
assert(state->numfree[0] != -1);
#endif
if (len < PyTuple_MAXSAVESIZE && if (len < PyTuple_MAXSAVESIZE &&
state->numfree[len] < PyTuple_MAXFREELIST && state->numfree[len] < PyTuple_MAXFREELIST &&
Py_IS_TYPE(op, &PyTuple_Type)) Py_IS_TYPE(op, &PyTuple_Type))
@ -984,6 +996,9 @@ _PyTuple_Fini(PyThreadState *tstate)
Py_CLEAR(state->free_list[0]); Py_CLEAR(state->free_list[0]);
_PyTuple_ClearFreeList(tstate); _PyTuple_ClearFreeList(tstate);
#ifdef Py_DEBUG
state->numfree[0] = -1;
#endif
#endif #endif
} }

View File

@ -335,6 +335,10 @@ _context_alloc(void)
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_context_state *state = &interp->context; struct _Py_context_state *state = &interp->context;
PyContext *ctx; PyContext *ctx;
#ifdef Py_DEBUG
// _context_alloc() must not be called after _PyContext_Fini()
assert(state->numfree != -1);
#endif
if (state->numfree) { if (state->numfree) {
state->numfree--; state->numfree--;
ctx = state->freelist; ctx = state->freelist;
@ -460,6 +464,10 @@ context_tp_dealloc(PyContext *self)
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_context_state *state = &interp->context; struct _Py_context_state *state = &interp->context;
#ifdef Py_DEBUG
// _context_alloc() must not be called after _PyContext_Fini()
assert(state->numfree != -1);
#endif
if (state->numfree < CONTEXT_FREELIST_MAXLEN) { if (state->numfree < CONTEXT_FREELIST_MAXLEN) {
state->numfree++; state->numfree++;
self->ctx_weakreflist = (PyObject *)state->freelist; self->ctx_weakreflist = (PyObject *)state->freelist;
@ -1290,6 +1298,10 @@ _PyContext_Fini(PyThreadState *tstate)
{ {
Py_CLEAR(_token_missing); Py_CLEAR(_token_missing);
_PyContext_ClearFreeList(tstate); _PyContext_ClearFreeList(tstate);
#ifdef Py_DEBUG
struct _Py_context_state *state = &tstate->interp->context;
state->numfree = -1;
#endif
_PyHamt_Fini(); _PyHamt_Fini();
} }