From a59e2a49e1d2dbf093656d60d2795e3f31a3621a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 13 Jan 2022 17:56:24 +0100 Subject: [PATCH] bpo-46070: _PyGC_Fini() untracks objects Py_EndInterpreter() now explicitly untracks all objects currently tracked by the GC. Previously, if an object was used later by another interpreter, calling PyObject_GC_UnTrack() on the object crashed if the previous or the next object of the PyGC_Head structure became a dangling pointer. --- .../2022-01-13-17-58-56.bpo-46070.q8IGth.rst | 5 ++++ Modules/gcmodule.c | 24 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-01-13-17-58-56.bpo-46070.q8IGth.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-01-13-17-58-56.bpo-46070.q8IGth.rst b/Misc/NEWS.d/next/Core and Builtins/2022-01-13-17-58-56.bpo-46070.q8IGth.rst new file mode 100644 index 00000000000000..4ed088f9898ebe --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-01-13-17-58-56.bpo-46070.q8IGth.rst @@ -0,0 +1,5 @@ +:c:func:`Py_EndInterpreter` now explicitly untracks all objects currently +tracked by the GC. Previously, if an object was used later by another +interpreter, calling :c:func:`PyObject_GC_UnTrack` on the object crashed if the +previous or the next object of the :c:type:`PyGC_Head` structure became a +dangling pointer. Patch by Victor Stinner. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 1808057a650e98..e22f031f574904 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2161,12 +2161,36 @@ _PyGC_DumpShutdownStats(PyInterpreterState *interp) } } + +static void +gc_fini_untrack(PyGC_Head *list) +{ + PyGC_Head *gc; + for (gc = GC_NEXT(list); gc != list; gc = GC_NEXT(list)) { + PyObject *op = FROM_GC(gc); + _PyObject_GC_UNTRACK(op); + } +} + + void _PyGC_Fini(PyInterpreterState *interp) { GCState *gcstate = &interp->gc; Py_CLEAR(gcstate->garbage); Py_CLEAR(gcstate->callbacks); + + if (!_Py_IsMainInterpreter(interp)) { + // bpo-46070: Explicitly untrack all objects currently tracked by the + // GC. Otherwise, if an object is used later by another interpreter, + // calling PyObject_GC_UnTrack() on the object crashs if the previous + // or the next object of the PyGC_Head structure became a dangling + // pointer. + for (int i = 0; i < NUM_GENERATIONS; i++) { + PyGC_Head *gen = GEN_HEAD(gcstate, i); + gc_fini_untrack(gen); + } + } } /* for debugging */