Skip to content

Commit

Permalink
[3.12] gh-116510: Fix crash during sub-interpreter shutdown (gh-124536)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nascheme authored Sep 27, 2024
1 parent c6f3f83 commit 69fd1f2
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -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.
29 changes: 26 additions & 3 deletions Modules/gcmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2174,6 +2174,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)
Expand All @@ -2182,9 +2189,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.
*/
for (int i = 0; i < NUM_GENERATIONS; i++) {
finalize_unlink_gc_head(&gcstate->generations[i].head);
}
finalize_unlink_gc_head(&gcstate->permanent_generation.head);
}

/* for debugging */
Expand Down

0 comments on commit 69fd1f2

Please sign in to comment.