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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy