]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-140652: Fix a crash in _interpchannels.list_all() after closing a channel (ПР...
authorSerhiy Storchaka <storchaka@gmail.com>
Wed, 18 Feb 2026 12:54:48 +0000 (14:54 +0200)
committerGitHub <noreply@github.com>
Wed, 18 Feb 2026 12:54:48 +0000 (14:54 +0200)
Lib/test/test__interpchannels.py
Lib/test/test_interpreters/test_channels.py
Misc/NEWS.d/next/Library/2026-01-12-19-39-57.gh-issue-140652.HvM9Bl.rst [new file with mode: 0644]
Modules/_interpchannelsmodule.c

index d7cf77368ef9f2e7e8a78b3e0219f8769843b2b9..2b0aba42896c06a5b7996ee63def4fde80418d24 100644 (file)
@@ -382,6 +382,38 @@ class ChannelTests(TestBase):
         self.assertEqual(id3, int(id2) + 1)
         self.assertEqual(set(after) - set(before), {id1, id2, id3})
 
+    def test_channel_list_all_closed(self):
+        id1 = _channels.create()
+        id2 = _channels.create()
+        id3 = _channels.create()
+        before = _channels.list_all()
+        expected = [info for info in before if info[0] != id2]
+        _channels.close(id2, force=True)
+        after = _channels.list_all()
+        self.assertEqual(set(after), set(expected))
+        self.assertEqual(len(after), len(before) - 1)
+
+    def test_channel_list_all_destroyed(self):
+        id1 = _channels.create()
+        id2 = _channels.create()
+        id3 = _channels.create()
+        before = _channels.list_all()
+        expected = [info for info in before if info[0] != id2]
+        _channels.destroy(id2)
+        after = _channels.list_all()
+        self.assertEqual(set(after), set(expected))
+        self.assertEqual(len(after), len(before) - 1)
+
+    def test_channel_list_all_released(self):
+        id1 = _channels.create()
+        id2 = _channels.create()
+        id3 = _channels.create()
+        before = _channels.list_all()
+        _channels.release(id2, send=True, recv=True)
+        after = _channels.list_all()
+        self.assertEqual(set(after), set(before))
+        self.assertEqual(len(after), len(before))
+
     def test_ids_global(self):
         id1 = _interpreters.create()
         out = _run_output(id1, dedent("""
index 52827357078b85760438febd2be497e26eb26173..5437792b5a7014a761d0045556b635c3cbbed450 100644 (file)
@@ -47,6 +47,12 @@ class TestChannels(TestBase):
         after = set(channels.list_all())
         self.assertEqual(after, created)
 
+    def test_list_all_closed(self):
+        created = [channels.create() for _ in range(3)]
+        rch, sch = created.pop(1)
+        rch.close()
+        self.assertEqual(set(channels.list_all()), set(created))
+
     def test_shareable(self):
         interp = interpreters.create()
         rch, sch = channels.create()
diff --git a/Misc/NEWS.d/next/Library/2026-01-12-19-39-57.gh-issue-140652.HvM9Bl.rst b/Misc/NEWS.d/next/Library/2026-01-12-19-39-57.gh-issue-140652.HvM9Bl.rst
new file mode 100644 (file)
index 0000000..bed126f
--- /dev/null
@@ -0,0 +1 @@
+Fix a crash in :func:`!_interpchannels.list_all` after closing a channel.
index ef9cf01ecbec5ee70a56a7eb91cdebf426e5a8bc..2933332ad465d4080763116822f49f5880d42abf 100644 (file)
@@ -1644,14 +1644,16 @@ _channels_list_all(_channels *channels, int64_t *count)
     if (ids == NULL) {
         goto done;
     }
-    _channelref *ref = channels->head;
-    for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
-        ids[i] = (struct channel_id_and_info){
-            .id = ref->cid,
-            .defaults = ref->chan->defaults,
-        };
+    int64_t i = 0;
+    for (_channelref *ref = channels->head; ref != NULL; ref = ref->next) {
+        if (ref->chan != NULL) {
+            ids[i++] = (struct channel_id_and_info){
+                .id = ref->cid,
+                .defaults = ref->chan->defaults,
+            };
+        }
     }
-    *count = channels->numopen;
+    *count = i;
 
     cids = ids;
 done: