Skip to content

Commit bcb1983

Browse files
authored
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()).
1 parent c96a61e commit bcb1983

File tree

6 files changed

+88
-3
lines changed

6 files changed

+88
-3
lines changed

Objects/floatobject.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ PyFloat_FromDouble(double fval)
116116
struct _Py_float_state *state = &interp->float_state;
117117
PyFloatObject *op = state->free_list;
118118
if (op != NULL) {
119+
#ifdef Py_DEBUG
120+
// PyFloat_FromDouble() must not be called after _PyFloat_Fini()
121+
assert(state->numfree != -1);
122+
#endif
119123
state->free_list = (PyFloatObject *) Py_TYPE(op);
120124
state->numfree--;
121125
}
@@ -219,6 +223,10 @@ float_dealloc(PyFloatObject *op)
219223
if (PyFloat_CheckExact(op)) {
220224
PyInterpreterState *interp = _PyInterpreterState_GET();
221225
struct _Py_float_state *state = &interp->float_state;
226+
#ifdef Py_DEBUG
227+
// float_dealloc() must not be called after _PyFloat_Fini()
228+
assert(state->numfree != -1);
229+
#endif
222230
if (state->numfree >= PyFloat_MAXFREELIST) {
223231
PyObject_FREE(op);
224232
return;
@@ -1984,10 +1992,11 @@ void
19841992
_PyFloat_ClearFreeList(PyThreadState *tstate)
19851993
{
19861994
struct _Py_float_state *state = &tstate->interp->float_state;
1987-
PyFloatObject *f = state->free_list, *next;
1988-
for (; f; f = next) {
1989-
next = (PyFloatObject*) Py_TYPE(f);
1995+
PyFloatObject *f = state->free_list;
1996+
while (f != NULL) {
1997+
PyFloatObject *next = (PyFloatObject*) Py_TYPE(f);
19901998
PyObject_FREE(f);
1999+
f = next;
19912000
}
19922001
state->free_list = NULL;
19932002
state->numfree = 0;
@@ -1997,6 +2006,10 @@ void
19972006
_PyFloat_Fini(PyThreadState *tstate)
19982007
{
19992008
_PyFloat_ClearFreeList(tstate);
2009+
#ifdef Py_DEBUG
2010+
struct _Py_float_state *state = &tstate->interp->float_state;
2011+
state->numfree = -1;
2012+
#endif
20002013
}
20012014

20022015
/* Print summary info about the state of the optimized allocator */

Objects/frameobject.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,10 @@ frame_dealloc(PyFrameObject *f)
595595
else {
596596
PyInterpreterState *interp = _PyInterpreterState_GET();
597597
struct _Py_frame_state *state = &interp->frame;
598+
#ifdef Py_DEBUG
599+
// frame_dealloc() must not be called after _PyFrame_Fini()
600+
assert(state->numfree != -1);
601+
#endif
598602
if (state->numfree < PyFrame_MAXFREELIST) {
599603
++state->numfree;
600604
f->f_back = state->free_list;
@@ -790,6 +794,10 @@ frame_alloc(PyCodeObject *code)
790794
}
791795
}
792796
else {
797+
#ifdef Py_DEBUG
798+
// frame_alloc() must not be called after _PyFrame_Fini()
799+
assert(state->numfree != -1);
800+
#endif
793801
assert(state->numfree > 0);
794802
--state->numfree;
795803
f = state->free_list;
@@ -1188,6 +1196,10 @@ void
11881196
_PyFrame_Fini(PyThreadState *tstate)
11891197
{
11901198
_PyFrame_ClearFreeList(tstate);
1199+
#ifdef Py_DEBUG
1200+
struct _Py_frame_state *state = &tstate->interp->frame;
1201+
state->numfree = -1;
1202+
#endif
11911203
}
11921204

11931205
/* Print summary info about the state of the optimized allocator */

Objects/genobject.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,6 +1430,11 @@ void
14301430
_PyAsyncGen_Fini(PyThreadState *tstate)
14311431
{
14321432
_PyAsyncGen_ClearFreeLists(tstate);
1433+
#ifdef Py_DEBUG
1434+
struct _Py_async_gen_state *state = &tstate->interp->async_gen;
1435+
state->value_numfree = -1;
1436+
state->asend_numfree = -1;
1437+
#endif
14331438
}
14341439

14351440

@@ -1474,6 +1479,10 @@ async_gen_asend_dealloc(PyAsyncGenASend *o)
14741479
Py_CLEAR(o->ags_sendval);
14751480
PyInterpreterState *interp = _PyInterpreterState_GET();
14761481
struct _Py_async_gen_state *state = &interp->async_gen;
1482+
#ifdef Py_DEBUG
1483+
// async_gen_asend_dealloc() must not be called after _PyAsyncGen_Fini()
1484+
assert(state->asend_numfree != -1);
1485+
#endif
14771486
if (state->asend_numfree < _PyAsyncGen_MAXFREELIST) {
14781487
assert(PyAsyncGenASend_CheckExact(o));
14791488
state->asend_freelist[state->asend_numfree++] = o;
@@ -1632,6 +1641,10 @@ async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval)
16321641
PyAsyncGenASend *o;
16331642
PyInterpreterState *interp = _PyInterpreterState_GET();
16341643
struct _Py_async_gen_state *state = &interp->async_gen;
1644+
#ifdef Py_DEBUG
1645+
// async_gen_asend_new() must not be called after _PyAsyncGen_Fini()
1646+
assert(state->asend_numfree != -1);
1647+
#endif
16351648
if (state->asend_numfree) {
16361649
state->asend_numfree--;
16371650
o = state->asend_freelist[state->asend_numfree];
@@ -1667,6 +1680,10 @@ async_gen_wrapped_val_dealloc(_PyAsyncGenWrappedValue *o)
16671680
Py_CLEAR(o->agw_val);
16681681
PyInterpreterState *interp = _PyInterpreterState_GET();
16691682
struct _Py_async_gen_state *state = &interp->async_gen;
1683+
#ifdef Py_DEBUG
1684+
// async_gen_wrapped_val_dealloc() must not be called after _PyAsyncGen_Fini()
1685+
assert(state->value_numfree != -1);
1686+
#endif
16701687
if (state->value_numfree < _PyAsyncGen_MAXFREELIST) {
16711688
assert(_PyAsyncGenWrappedValue_CheckExact(o));
16721689
state->value_freelist[state->value_numfree++] = o;
@@ -1737,6 +1754,10 @@ _PyAsyncGenValueWrapperNew(PyObject *val)
17371754

17381755
PyInterpreterState *interp = _PyInterpreterState_GET();
17391756
struct _Py_async_gen_state *state = &interp->async_gen;
1757+
#ifdef Py_DEBUG
1758+
// _PyAsyncGenValueWrapperNew() must not be called after _PyAsyncGen_Fini()
1759+
assert(state->value_numfree != -1);
1760+
#endif
17401761
if (state->value_numfree) {
17411762
state->value_numfree--;
17421763
o = state->value_freelist[state->value_numfree];

Objects/listobject.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ void
111111
_PyList_Fini(PyThreadState *tstate)
112112
{
113113
_PyList_ClearFreeList(tstate);
114+
#ifdef Py_DEBUG
115+
struct _Py_list_state *state = &tstate->interp->list;
116+
state->numfree = -1;
117+
#endif
114118
}
115119

116120
/* Print summary info about the state of the optimized allocator */
@@ -135,6 +139,10 @@ PyList_New(Py_ssize_t size)
135139
PyInterpreterState *interp = _PyInterpreterState_GET();
136140
struct _Py_list_state *state = &interp->list;
137141
PyListObject *op;
142+
#ifdef Py_DEBUG
143+
// PyList_New() must not be called after _PyList_Fini()
144+
assert(state->numfree != -1);
145+
#endif
138146
if (state->numfree) {
139147
state->numfree--;
140148
op = state->free_list[state->numfree];
@@ -330,6 +338,10 @@ list_dealloc(PyListObject *op)
330338
}
331339
PyInterpreterState *interp = _PyInterpreterState_GET();
332340
struct _Py_list_state *state = &interp->list;
341+
#ifdef Py_DEBUG
342+
// list_dealloc() must not be called after _PyList_Fini()
343+
assert(state->numfree != -1);
344+
#endif
333345
if (state->numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) {
334346
state->free_list[state->numfree++] = op;
335347
}

Objects/tupleobject.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ tuple_alloc(struct _Py_tuple_state *state, Py_ssize_t size)
5454
return NULL;
5555
}
5656
#if PyTuple_MAXSAVESIZE > 0
57+
#ifdef Py_DEBUG
58+
// tuple_alloc() must not be called after _PyTuple_Fini()
59+
assert(state->numfree[0] != -1);
60+
#endif
5761
if (size < PyTuple_MAXSAVESIZE && (op = state->free_list[size]) != NULL) {
5862
assert(size != 0);
5963
state->free_list[size] = (PyTupleObject *) op->ob_item[0];
@@ -102,6 +106,10 @@ PyTuple_New(Py_ssize_t size)
102106
}
103107
#if PyTuple_MAXSAVESIZE > 0
104108
if (size == 0) {
109+
#ifdef Py_DEBUG
110+
// PyTuple_New() must not be called after _PyTuple_Fini()
111+
assert(state->numfree[0] != -1);
112+
#endif
105113
state->free_list[0] = op;
106114
++state->numfree[0];
107115
Py_INCREF(op); /* extra INCREF so that this is never freed */
@@ -227,6 +235,10 @@ tupledealloc(PyTupleObject *op)
227235
#if PyTuple_MAXSAVESIZE > 0
228236
PyInterpreterState *interp = _PyInterpreterState_GET();
229237
struct _Py_tuple_state *state = &interp->tuple;
238+
#ifdef Py_DEBUG
239+
// tupledealloc() must not be called after _PyTuple_Fini()
240+
assert(state->numfree[0] != -1);
241+
#endif
230242
if (len < PyTuple_MAXSAVESIZE &&
231243
state->numfree[len] < PyTuple_MAXFREELIST &&
232244
Py_IS_TYPE(op, &PyTuple_Type))
@@ -984,6 +996,9 @@ _PyTuple_Fini(PyThreadState *tstate)
984996
Py_CLEAR(state->free_list[0]);
985997

986998
_PyTuple_ClearFreeList(tstate);
999+
#ifdef Py_DEBUG
1000+
state->numfree[0] = -1;
1001+
#endif
9871002
#endif
9881003
}
9891004

Python/context.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,10 @@ _context_alloc(void)
335335
PyInterpreterState *interp = _PyInterpreterState_GET();
336336
struct _Py_context_state *state = &interp->context;
337337
PyContext *ctx;
338+
#ifdef Py_DEBUG
339+
// _context_alloc() must not be called after _PyContext_Fini()
340+
assert(state->numfree != -1);
341+
#endif
338342
if (state->numfree) {
339343
state->numfree--;
340344
ctx = state->freelist;
@@ -460,6 +464,10 @@ context_tp_dealloc(PyContext *self)
460464

461465
PyInterpreterState *interp = _PyInterpreterState_GET();
462466
struct _Py_context_state *state = &interp->context;
467+
#ifdef Py_DEBUG
468+
// _context_alloc() must not be called after _PyContext_Fini()
469+
assert(state->numfree != -1);
470+
#endif
463471
if (state->numfree < CONTEXT_FREELIST_MAXLEN) {
464472
state->numfree++;
465473
self->ctx_weakreflist = (PyObject *)state->freelist;
@@ -1290,6 +1298,10 @@ _PyContext_Fini(PyThreadState *tstate)
12901298
{
12911299
Py_CLEAR(_token_missing);
12921300
_PyContext_ClearFreeList(tstate);
1301+
#ifdef Py_DEBUG
1302+
struct _Py_context_state *state = &tstate->interp->context;
1303+
state->numfree = -1;
1304+
#endif
12931305
_PyHamt_Fini();
12941306
}
12951307

0 commit comments

Comments
 (0)