https://github.com/python/cpython/commit/fd9365417dcbba1630c70398cdb2b19d0970498d commit: fd9365417dcbba1630c70398cdb2b19d0970498d branch: 3.14 author: Miss Islington (bot) <[email protected]> committer: kumaraditya303 <[email protected]> date: 2026-10-20T11:31:15Z summary:
[3.14] gh-146065: Fix NULL dereference in FutureIter_am_send (GH-158468) (#159871) gh-146065: Fix NULL dereference in FutureIter_am_send (GH-158468) (cherry picked from commit 66e391d14ba42218a4bf604973f584853440d6c1) Co-authored-by: Michael J. Sullivan <[email protected]> files: A Misc/NEWS.d/next/Library/2026-03-23-00-04-13.gh-issue-146065.FIdn8D.rst M Lib/test/test_asyncio/test_futures.py M Modules/_asynciomodule.c diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index f3cfb468e3f092..e615eb41f74f19 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -709,6 +709,24 @@ def test_future_cancelled_exception_refcycles(self): self.assertListEqual(gc.get_referrers(exc), []) + 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) + + def test_futureiter_send_after_close_no_crash(self): + fut = self._new_future(loop=self.loop) + it = fut.__await__() + next(it) + it.close() + 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..db91ce76198c01 --- /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 crash in asyncio.Future iterator when send() is +called after throw() or close(). diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index d20ecf308e419c..ba1db8be93efb7 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -1835,10 +1835,9 @@ FutureIter_dealloc(PyObject *it) } static PySendResult -FutureIter_am_send_lock_held(futureiterobject *it, PyObject **result) +FutureIter_am_send_lock_held(FutureObj *fut, PyObject **result) { PyObject *res; - FutureObj *fut = it->future; _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); *result = NULL; @@ -1869,11 +1868,24 @@ FutureIter_am_send(PyObject *op, PyObject **result) { futureiterobject *it = (futureiterobject*)op; + + FutureObj *fut; + Py_BEGIN_CRITICAL_SECTION(op); + fut = (FutureObj*)Py_XNewRef(it->future); + Py_END_CRITICAL_SECTION(); + + if (fut == 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); - res = FutureIter_am_send_lock_held(it, result); + Py_BEGIN_CRITICAL_SECTION(fut); + res = FutureIter_am_send_lock_held(fut, result); Py_END_CRITICAL_SECTION(); + Py_DECREF(fut); return res; } @@ -1967,7 +1979,9 @@ FutureIter_throw(PyObject *op, PyObject *const *args, Py_ssize_t nargs) goto fail; } + Py_BEGIN_CRITICAL_SECTION(self); Py_CLEAR(self->future); + Py_END_CRITICAL_SECTION(); PyErr_Restore(type, val, tb); @@ -1980,6 +1994,16 @@ FutureIter_throw(PyObject *op, PyObject *const *args, Py_ssize_t nargs) return NULL; } +static PyObject * +FutureIter_close(PyObject *self, PyObject *arg) +{ + futureiterobject *it = (futureiterobject*)self; + Py_BEGIN_CRITICAL_SECTION(self); + Py_CLEAR(it->future); + Py_END_CRITICAL_SECTION(); + Py_RETURN_NONE; +} + static int FutureIter_clear(PyObject *op) { @@ -1988,13 +2012,6 @@ FutureIter_clear(PyObject *op) return 0; } -static PyObject * -FutureIter_close(PyObject *self, PyObject *arg) -{ - (void)FutureIter_clear(self); - Py_RETURN_NONE; -} - static int FutureIter_traverse(PyObject *op, visitproc visit, void *arg) { _______________________________________________ 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]
