From b257f320ce6044c658e3cf086b1ae4b4c6380515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sat, 28 Mar 2026 14:35:52 +0100 Subject: [PATCH 1/4] gh-143376: validate usages of `_interpchannels.ChannelID` in `_channelid_shared` --- Lib/test/test_interpreters/test_channels.py | 24 +++++++++++++++++++ ...-03-28-14-34-18.gh-issue-143376.FvWTwi.rst | 2 ++ Modules/_interpchannelsmodule.c | 11 +++++++++ 3 files changed, 37 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-03-28-14-34-18.gh-issue-143376.FvWTwi.rst diff --git a/Lib/test/test_interpreters/test_channels.py b/Lib/test/test_interpreters/test_channels.py index 5437792b5a7014..0670522dc88b58 100644 --- a/Lib/test/test_interpreters/test_channels.py +++ b/Lib/test/test_interpreters/test_channels.py @@ -30,6 +30,30 @@ def test_highlevel_reloaded(self): # See gh-115490 (https://github.com/python/cpython/issues/115490). importlib.reload(channels) + def test_channel_id_types(self): + # See https://github.com/python/cpython/issues/143376. + class End: + __slots__ = () + def __new__(cls, chan=None): + return object.__new__(cls) + @property + def _id(self): + return object() + + class Send(End): pass + class Recv(End): pass + + _ = importlib.reload(_channels) + _._register_end_types(Send, Recv) + chan = _._channel_id(_.create(), _resolve=True) + interp = interpreters.create() + # The TypeError exception arises from our internal check, + # but subinterpreters use a generic exception message instead + # while retaining the original exception type. + err = "does not support cross-interpreter data" + with self.assertRaisesRegex(TypeError, err): + interp.prepare_main(chan=Send(chan)) + class TestChannels(TestBase): diff --git a/Misc/NEWS.d/next/Library/2026-03-28-14-34-18.gh-issue-143376.FvWTwi.rst b/Misc/NEWS.d/next/Library/2026-03-28-14-34-18.gh-issue-143376.FvWTwi.rst new file mode 100644 index 00000000000000..981e0ede58fde8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-03-28-14-34-18.gh-issue-143376.FvWTwi.rst @@ -0,0 +1,2 @@ +:mod:`concurrent.interpreters`: fix a crash when internal cross-interpreter +channel ends have incorrect channel IDs. Patch by Bénédikt Tran. diff --git a/Modules/_interpchannelsmodule.c b/Modules/_interpchannelsmodule.c index 3c356cb40d2bca..830f94c254e455 100644 --- a/Modules/_interpchannelsmodule.c +++ b/Modules/_interpchannelsmodule.c @@ -2633,6 +2633,17 @@ _channelid_from_xid(_PyXIData_t *data) static int _channelid_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data) { + module_state *st = _get_current_module_state(); + if (st == NULL) { + return -1; + } + if (!PyObject_IsInstance(obj, (PyObject *)st->ChannelIDType)) { + PyErr_Format(PyExc_TypeError, + "'_id' attribute must be an %N object, not %T", + st->ChannelIDType, obj); + return -1; + } + if (_PyXIData_InitWithSize( data, tstate->interp, sizeof(struct _channelid_xid), obj, _channelid_from_xid From 164bd7f0a763f5a4d0aa4793d726fc87f863f41d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 19 Oct 2026 10:48:02 -0700 Subject: [PATCH 2/4] fix imports --- Lib/test/test_interpreters/test_channels.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_interpreters/test_channels.py b/Lib/test/test_interpreters/test_channels.py index 06a84f18d6e431..6e644dc70bd5a8 100644 --- a/Lib/test/test_interpreters/test_channels.py +++ b/Lib/test/test_interpreters/test_channels.py @@ -1,3 +1,4 @@ +import importlib import pickle import threading from textwrap import dedent From 0d2bf9cde1aad6dced0366a965133a1d2f4157b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 19 Oct 2026 13:27:34 -0700 Subject: [PATCH 3/4] try to see if the issue is because of bad registered channels --- Lib/test/test_interpreters/test_channels.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/test/test_interpreters/test_channels.py b/Lib/test/test_interpreters/test_channels.py index 6e644dc70bd5a8..11e9db144bfd2c 100644 --- a/Lib/test/test_interpreters/test_channels.py +++ b/Lib/test/test_interpreters/test_channels.py @@ -49,6 +49,8 @@ class Send(End): pass class Recv(End): pass _ = importlib.reload(_channels) + # ensure that the following tests do not have the registered bad types + self.addCleanup(importlib.reload, _channels) _._register_end_types(Send, Recv) chan = _._channel_id(_.create(), _resolve=True) interp = interpreters.create() From cb1aeec12efda1ea50db15a21c52b517e6d7c570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 19 Oct 2026 15:35:33 -0700 Subject: [PATCH 4/4] fix test on iOS/Android --- Lib/test/test_interpreters/test_channels.py | 30 ++++++++++++--------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_interpreters/test_channels.py b/Lib/test/test_interpreters/test_channels.py index 11e9db144bfd2c..cd53a4f61bedbd 100644 --- a/Lib/test/test_interpreters/test_channels.py +++ b/Lib/test/test_interpreters/test_channels.py @@ -1,4 +1,3 @@ -import importlib import pickle import threading from textwrap import dedent @@ -9,7 +8,7 @@ # Raise SkipTest if subinterpreters not supported. _channels = import_helper.import_module('_interpchannels') from concurrent import interpreters -from test.support import channels +from test.support import channels, force_not_colorized from .utils import _run_output, TestBase @@ -35,8 +34,14 @@ def test_highlevel_reloaded(self): importlib.reload(channels) """)); + @force_not_colorized def test_channel_id_types(self): # See https://github.com/python/cpython/issues/143376. + code = """\ + import _interpchannels + import re + from concurrent import interpreters + class End: __slots__ = () def __new__(cls, chan=None): @@ -48,18 +53,19 @@ def _id(self): class Send(End): pass class Recv(End): pass - _ = importlib.reload(_channels) - # ensure that the following tests do not have the registered bad types - self.addCleanup(importlib.reload, _channels) - _._register_end_types(Send, Recv) - chan = _._channel_id(_.create(), _resolve=True) + _interpchannels._register_end_types(Send, Recv) + chan = _interpchannels._channel_id(_interpchannels.create(), _resolve=True) interp = interpreters.create() - # The TypeError exception arises from our internal check, - # but subinterpreters use a generic exception message instead - # while retaining the original exception type. - err = "does not support cross-interpreter data" - with self.assertRaisesRegex(TypeError, err): + try: interp.prepare_main(chan=Send(chan)) + finally: + interp.close() + """ + + out, err = self.assert_python_failure("-c", code) + self.assertEqual(out, '') + errmsg = "TypeError: '_id' attribute must be an _interpchannels.ChannelID object, not object" + self.assertIn(errmsg, err) class TestChannels(TestBase):