diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index 9385a65e52813e..d56c2201d90ba2 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -755,6 +755,16 @@ def test_future_disallow_multiple_initialization(self): with self.assertRaises(RuntimeError, msg="is already initialized"): f.__init__(loop=self.loop) + def test_futureiter_send_after_throw_no_crash(self): + fut = self._new_future(loop=self.loop) + it = fut.__await__() + next(it) + with self.assertRaises(RuntimeError): + it.throw(RuntimeError) + with self.assertRaises(StopIteration): + it.send(None) + + @unittest.skipUnless(hasattr(futures, '_CFuture'), 'requires the C _asyncio module') class CFutureTests(BaseFutureTests, test_utils.TestCase): diff --git a/Misc/NEWS.d/next/Library/2026-03-23-00-04-13.gh-issue-146065.FIdn8D.rst b/Misc/NEWS.d/next/Library/2026-03-23-00-04-13.gh-issue-146065.FIdn8D.rst new file mode 100644 index 00000000000000..c30032cd3a16bb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-03-23-00-04-13.gh-issue-146065.FIdn8D.rst @@ -0,0 +1,2 @@ +Fix a NULL pointer dereference in asyncio.Future iterator when send() is +called after throw() or close(), which previously could cause a crash. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 8eb8e191530a33..aa819ae75c217f 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -1872,6 +1872,11 @@ FutureIter_am_send(PyObject *op, PyObject **result) { futureiterobject *it = (futureiterobject*)op; + if (it->future == NULL) { + PyErr_SetNone(PyExc_StopIteration); + *result = NULL; + return PYGEN_ERROR; + } /* arg is unused, see the comment on FutureIter_send for clarification */ PySendResult res; Py_BEGIN_CRITICAL_SECTION(it->future);