[3.13] gh-155997: Fix list_all() if an interpreter is destroyed during the call (GH-155998) (GH-156006)

serhiy-storchaka <[email protected]>
Newsgroups gmane.comp.python.cvs
Message-ID <[email protected]>
https://github.com/python/cpython/commit/5b49a29b0d8d916837e4b9f51649aa1954a5d89b
commit: 5b49a29b0d8d916837e4b9f51649aa1954a5d89b
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-08-18T12:41:07Z
summary:

[3.13] gh-155997: Fix list_all() if an interpreter is destroyed during the call (GH-155998) (GH-156006)

Creating the Interpreter objects can start a garbage collection which
finalizes an object owning the last reference to a listed interpreter.
Skip interpreters which no longer exist instead of failing.
(cherry picked from commit 60dff5a47b20a7efb6e43c571617b9139474bfe9)

Co-authored-by: Serhiy Storchaka <[email protected]>

files:
A Misc/NEWS.d/next/Tests/2026-08-18-13-41-00.gh-issue-155997.CjbD1F.rst
M Lib/test/support/interpreters/__init__.py
M Lib/test/test_interpreters/test_api.py

diff --git a/Lib/test/support/interpreters/__init__.py b/Lib/test/support/interpreters/__init__.py
index e067f259364d2aa..ad988f180f28cb2 100644
--- a/Lib/test/support/interpreters/__init__.py
+++ b/Lib/test/support/interpreters/__init__.py
@@ -79,8 +79,14 @@ def create():
 
 def list_all():
     """Return all existing interpreters."""
-    return [Interpreter(id, _whence=whence)
-            for id, whence in _interpreters.list_all(require_ready=True)]
+    interps = []
+    for id, whence in _interpreters.list_all(require_ready=True):
+        try:
+            interps.append(Interpreter(id, _whence=whence))
+        except InterpreterNotFoundError:
+            # It was destroyed after it was listed.
+            pass
+    return interps
 
 
 def get_current():
diff --git a/Lib/test/test_interpreters/test_api.py b/Lib/test/test_interpreters/test_api.py
index b9c0c45e0160bfd..6e6b9453c24da9f 100644
--- a/Lib/test/test_interpreters/test_api.py
+++ b/Lib/test/test_interpreters/test_api.py
@@ -231,6 +231,21 @@ def test_idempotent(self):
         for interp1, interp2 in zip(actual, expected):
             self.assertIs(interp1, interp2)
 
+    def test_destroyed_by_gc(self):
+        # gh-155997: the interpreter is destroyed while list_all() runs.
+        interp = interpreters.create()
+        interpid = interp.id
+        cycle = []
+        cycle.append(cycle)
+        cycle.append(interp)
+        # The cycle holds the only reference, so only the collector frees it.
+        with support.disable_gc():
+            del interp, cycle
+
+        with support.gc_threshold(1):
+            ids = [i.id for i in interpreters.list_all()]
+        self.assertNotIn(interpid, ids)
+
     def test_created_with_capi(self):
         mainid, *_ = _interpreters.get_main()
         interpid1 = _interpreters.create()
diff --git a/Misc/NEWS.d/next/Tests/2026-08-18-13-41-00.gh-issue-155997.CjbD1F.rst b/Misc/NEWS.d/next/Tests/2026-08-18-13-41-00.gh-issue-155997.CjbD1F.rst
new file mode 100644
index 000000000000000..e55c531130055b0
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2026-08-18-13-41-00.gh-issue-155997.CjbD1F.rst
@@ -0,0 +1,3 @@
+Fix :func:`!test.support.interpreters.list_all`.  It failed if an interpreter
+was destroyed during the call, in particular by a garbage collection which
+finalized the object owning the last reference to it.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.