gh-116510: Fix crash during sub-interpreter shutdown (gh-124645)

Fix a bug that can cause a crash when sub-interpreters use "basic"
single-phase extension modules.  Shared objects could refer to PyGC_Head
nodes that had been freed as part of interpreter shutdown.
This commit is contained in:
Neil Schemenauer 2024-09-26 19:33:07 -07:00 committed by GitHub
parent 98b2ed7e23
commit 6f9525dd3f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 29 additions and 3 deletions

View File

@ -0,0 +1,3 @@
Fix a bug that can cause a crash when sub-interpreters use "basic"
single-phase extension modules. Shared objects could refer to PyGC_Head
nodes that had been freed as part of interpreter cleanup.

View File

@ -1944,6 +1944,13 @@ _PyGC_DumpShutdownStats(PyInterpreterState *interp)
}
}
static void
finalize_unlink_gc_head(PyGC_Head *gc) {
PyGC_Head *prev = GC_PREV(gc);
PyGC_Head *next = GC_NEXT(gc);
_PyGCHead_SET_NEXT(prev, next);
_PyGCHead_SET_PREV(next, prev);
}
void
_PyGC_Fini(PyInterpreterState *interp)
@ -1952,9 +1959,25 @@ _PyGC_Fini(PyInterpreterState *interp)
Py_CLEAR(gcstate->garbage);
Py_CLEAR(gcstate->callbacks);
/* We expect that none of this interpreters objects are shared
with other interpreters.
See https://github.com/python/cpython/issues/90228. */
/* Prevent a subtle bug that affects sub-interpreters that use basic
* single-phase init extensions (m_size == -1). Those extensions cause objects
* to be shared between interpreters, via the PyDict_Update(mdict, m_copy) call
* in import_find_extension().
*
* If they are GC objects, their GC head next or prev links could refer to
* the interpreter _gc_runtime_state PyGC_Head nodes. Those nodes go away
* when the interpreter structure is freed and so pointers to them become
* invalid. If those objects are still used by another interpreter and
* UNTRACK is called on them, a crash will happen. We untrack the nodes
* here to avoid that.
*
* This bug was originally fixed when reported as gh-90228. The bug was
* re-introduced in gh-94673.
*/
finalize_unlink_gc_head(&gcstate->young.head);
finalize_unlink_gc_head(&gcstate->old[0].head);
finalize_unlink_gc_head(&gcstate->old[1].head);
finalize_unlink_gc_head(&gcstate->permanent_generation.head);
}
/* for debugging */