mirror of https://github.com/python/cpython
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:
parent
c96a61e816
commit
bcb198385d
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue