diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index 2184b2091f84ee..cfcd43dbe725ae 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -641,6 +641,14 @@ def test_future_del_segfault(self): with self.assertRaises(AttributeError): del fut._log_traceback + def test_future_iter_get_referents_segfault(self): + # See https://github.com/python/cpython/issues/122695 + import _asyncio + it = iter(self._new_future(loop=self.loop)) + del it + evil = gc.get_referents(_asyncio) + + @unittest.skipUnless(hasattr(futures, '_CFuture'), 'requires the C _asyncio module') diff --git a/Misc/NEWS.d/next/Library/2024-08-08-14-16-41.gh-issue-122695.f7pwBv.rst b/Misc/NEWS.d/next/Library/2024-08-08-14-16-41.gh-issue-122695.f7pwBv.rst new file mode 100644 index 00000000000000..cc6bc38f419462 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-08-08-14-16-41.gh-issue-122695.f7pwBv.rst @@ -0,0 +1,2 @@ +Fixed double-free when using :func:`gc.get_referents` with a freed +:class:`asyncio.Future` iterator. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 6b969edca29804..cf6257834cdeb3 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -3607,13 +3607,8 @@ module_traverse(PyObject *mod, visitproc visit, void *arg) Py_VISIT(state->context_kwname); - // Visit freelist. - PyObject *next = (PyObject*) state->fi_freelist; - while (next != NULL) { - PyObject *current = next; - Py_VISIT(current); - next = (PyObject*) ((futureiterobject*) current)->future; - } + // GH-122695: Do not traverse the freelist here, as that can cause problems + // with gc.get_referents() return 0; }