@@ -1944,6 +1944,13 @@ _PyGC_DumpShutdownStats(PyInterpreterState *interp)
19441944 }
19451945}
19461946
1947+ static void
1948+ finalize_unlink_gc_head (PyGC_Head * gc ) {
1949+ PyGC_Head * prev = GC_PREV (gc );
1950+ PyGC_Head * next = GC_NEXT (gc );
1951+ _PyGCHead_SET_NEXT (prev , next );
1952+ _PyGCHead_SET_PREV (next , prev );
1953+ }
19471954
19481955void
19491956_PyGC_Fini (PyInterpreterState * interp )
@@ -1952,9 +1959,25 @@ _PyGC_Fini(PyInterpreterState *interp)
19521959 Py_CLEAR (gcstate -> garbage );
19531960 Py_CLEAR (gcstate -> callbacks );
19541961
1955- /* We expect that none of this interpreters objects are shared
1956- with other interpreters.
1957- See https://github.com/python/cpython/issues/90228. */
1962+ /* Prevent a subtle bug that affects sub-interpreters that use basic
1963+ * single-phase init extensions (m_size == -1). Those extensions cause objects
1964+ * to be shared between interpreters, via the PyDict_Update(mdict, m_copy) call
1965+ * in import_find_extension().
1966+ *
1967+ * If they are GC objects, their GC head next or prev links could refer to
1968+ * the interpreter _gc_runtime_state PyGC_Head nodes. Those nodes go away
1969+ * when the interpreter structure is freed and so pointers to them become
1970+ * invalid. If those objects are still used by another interpreter and
1971+ * UNTRACK is called on them, a crash will happen. We untrack the nodes
1972+ * here to avoid that.
1973+ *
1974+ * This bug was originally fixed when reported as gh-90228. The bug was
1975+ * re-introduced in gh-94673.
1976+ */
1977+ finalize_unlink_gc_head (& gcstate -> young .head );
1978+ finalize_unlink_gc_head (& gcstate -> old [0 ].head );
1979+ finalize_unlink_gc_head (& gcstate -> old [1 ].head );
1980+ finalize_unlink_gc_head (& gcstate -> permanent_generation .head );
19581981}
19591982
19601983/* for debugging */
0 commit comments