@@ -2174,6 +2174,13 @@ _PyGC_DumpShutdownStats(PyInterpreterState *interp)
2174
2174
}
2175
2175
}
2176
2176
2177
+ static void
2178
+ finalize_unlink_gc_head (PyGC_Head * gc ) {
2179
+ PyGC_Head * prev = GC_PREV (gc );
2180
+ PyGC_Head * next = GC_NEXT (gc );
2181
+ _PyGCHead_SET_NEXT (prev , next );
2182
+ _PyGCHead_SET_PREV (next , prev );
2183
+ }
2177
2184
2178
2185
void
2179
2186
_PyGC_Fini (PyInterpreterState * interp )
@@ -2182,9 +2189,25 @@ _PyGC_Fini(PyInterpreterState *interp)
2182
2189
Py_CLEAR (gcstate -> garbage );
2183
2190
Py_CLEAR (gcstate -> callbacks );
2184
2191
2185
- /* We expect that none of this interpreters objects are shared
2186
- with other interpreters.
2187
- See https://github.com/python/cpython/issues/90228. */
2192
+ /* Prevent a subtle bug that affects sub-interpreters that use basic
2193
+ * single-phase init extensions (m_size == -1). Those extensions cause objects
2194
+ * to be shared between interpreters, via the PyDict_Update(mdict, m_copy) call
2195
+ * in import_find_extension().
2196
+ *
2197
+ * If they are GC objects, their GC head next or prev links could refer to
2198
+ * the interpreter _gc_runtime_state PyGC_Head nodes. Those nodes go away
2199
+ * when the interpreter structure is freed and so pointers to them become
2200
+ * invalid. If those objects are still used by another interpreter and
2201
+ * UNTRACK is called on them, a crash will happen. We untrack the nodes
2202
+ * here to avoid that.
2203
+ *
2204
+ * This bug was originally fixed when reported as gh-90228. The bug was
2205
+ * re-introduced in gh-94673.
2206
+ */
2207
+ for (int i = 0 ; i < NUM_GENERATIONS ; i ++ ) {
2208
+ finalize_unlink_gc_head (& gcstate -> generations [i ].head );
2209
+ }
2210
+ finalize_unlink_gc_head (& gcstate -> permanent_generation .head );
2188
2211
}
2189
2212
2190
2213
/* for debugging */
0 commit comments