]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-40887: Don't use finalized free lists (GH-20700)
authorVictor Stinner <vstinner@python.org>
Mon, 8 Jun 2020 00:14:47 +0000 (02:14 +0200)
committerGitHub <noreply@github.com>
Mon, 8 Jun 2020 00:14:47 +0000 (02:14 +0200)
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()).

Objects/floatobject.c
Objects/frameobject.c
Objects/genobject.c
Objects/listobject.c
Objects/tupleobject.c
Python/context.c

index d72fd21f95fafa58a35e4baf19c95bc69e26222c..65625fe88cad868f37239e0b253d4d63bde7a783 100644 (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 */
index 0fe9f2a6666b24b529ce6f163b224cab8c798ff4..0dad42ee7bff33c0005268267a78a165843549bb 100644 (file)
@@ -595,6 +595,10 @@ frame_dealloc(PyFrameObject *f)
     else {
         PyInterpreterState *interp = _PyInterpreterState_GET();
         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) {
             ++state->numfree;
             f->f_back = state->free_list;
@@ -790,6 +794,10 @@ frame_alloc(PyCodeObject *code)
         }
     }
     else {
+#ifdef Py_DEBUG
+        // frame_alloc() must not be called after _PyFrame_Fini()
+        assert(state->numfree != -1);
+#endif
         assert(state->numfree > 0);
         --state->numfree;
         f = state->free_list;
@@ -1188,6 +1196,10 @@ void
 _PyFrame_Fini(PyThreadState *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 */
index f7dbfd74864193ca7caa9fef1cac98c2b02ced14..4207d5326cca12df0b9fa60de0bb4211a309b5c2 100644 (file)
@@ -1430,6 +1430,11 @@ void
 _PyAsyncGen_Fini(PyThreadState *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);
     PyInterpreterState *interp = _PyInterpreterState_GET();
     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) {
         assert(PyAsyncGenASend_CheckExact(o));
         state->asend_freelist[state->asend_numfree++] = o;
@@ -1632,6 +1641,10 @@ async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval)
     PyAsyncGenASend *o;
     PyInterpreterState *interp = _PyInterpreterState_GET();
     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) {
         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);
     PyInterpreterState *interp = _PyInterpreterState_GET();
     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) {
         assert(_PyAsyncGenWrappedValue_CheckExact(o));
         state->value_freelist[state->value_numfree++] = o;
@@ -1737,6 +1754,10 @@ _PyAsyncGenValueWrapperNew(PyObject *val)
 
     PyInterpreterState *interp = _PyInterpreterState_GET();
     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) {
         state->value_numfree--;
         o = state->value_freelist[state->value_numfree];
index 043256d8adbf5c0faf95f3a839f045aa3c49a7ad..22cdbe3cfdd41d3bcfbd5f9d6f2ca498389e28da 100644 (file)
@@ -111,6 +111,10 @@ void
 _PyList_Fini(PyThreadState *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 */
@@ -135,6 +139,10 @@ PyList_New(Py_ssize_t size)
     PyInterpreterState *interp = _PyInterpreterState_GET();
     struct _Py_list_state *state = &interp->list;
     PyListObject *op;
+#ifdef Py_DEBUG
+    // PyList_New() must not be called after _PyList_Fini()
+    assert(state->numfree != -1);
+#endif
     if (state->numfree) {
         state->numfree--;
         op = state->free_list[state->numfree];
@@ -330,6 +338,10 @@ list_dealloc(PyListObject *op)
     }
     PyInterpreterState *interp = _PyInterpreterState_GET();
     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)) {
         state->free_list[state->numfree++] = op;
     }
index 951cd1faf7e8fce4b79481e8ca7208768245f72f..8bfa0894a79d4b915663244dffb64901e1ab73e8 100644 (file)
@@ -54,6 +54,10 @@ tuple_alloc(struct _Py_tuple_state *state, Py_ssize_t size)
         return NULL;
     }
 #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) {
         assert(size != 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 (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->numfree[0];
         Py_INCREF(op);          /* extra INCREF so that this is never freed */
@@ -227,6 +235,10 @@ tupledealloc(PyTupleObject *op)
 #if PyTuple_MAXSAVESIZE > 0
         PyInterpreterState *interp = _PyInterpreterState_GET();
         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 &&
             state->numfree[len] < PyTuple_MAXFREELIST &&
             Py_IS_TYPE(op, &PyTuple_Type))
@@ -984,6 +996,9 @@ _PyTuple_Fini(PyThreadState *tstate)
     Py_CLEAR(state->free_list[0]);
 
     _PyTuple_ClearFreeList(tstate);
+#ifdef Py_DEBUG
+    state->numfree[0] = -1;
+#endif
 #endif
 }
 
index 3cf8db4c90cdfef78e1e5fb4e40524758ba93243..dedbca99384c795e052673299649d67ef9bd8688 100644 (file)
@@ -335,6 +335,10 @@ _context_alloc(void)
     PyInterpreterState *interp = _PyInterpreterState_GET();
     struct _Py_context_state *state = &interp->context;
     PyContext *ctx;
+#ifdef Py_DEBUG
+    // _context_alloc() must not be called after _PyContext_Fini()
+    assert(state->numfree != -1);
+#endif
     if (state->numfree) {
         state->numfree--;
         ctx = state->freelist;
@@ -460,6 +464,10 @@ context_tp_dealloc(PyContext *self)
 
     PyInterpreterState *interp = _PyInterpreterState_GET();
     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) {
         state->numfree++;
         self->ctx_weakreflist = (PyObject *)state->freelist;
@@ -1290,6 +1298,10 @@ _PyContext_Fini(PyThreadState *tstate)
 {
     Py_CLEAR(_token_missing);
     _PyContext_ClearFreeList(tstate);
+#ifdef Py_DEBUG
+    struct _Py_context_state *state = &tstate->interp->context;
+    state->numfree = -1;
+#endif
     _PyHamt_Fini();
 }