Skip to content

Commit fd93654

Browse files
[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 66e391d) Co-authored-by: Michael J. Sullivan <sully@msully.net>
1 parent 09fe347 commit fd93654

3 files changed

Lines changed: 48 additions & 11 deletions

File tree

‎Lib/test/test_asyncio/test_futures.py‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,24 @@ def test_future_cancelled_exception_refcycles(self):
709709
self.assertListEqual(gc.get_referrers(exc), [])
710710

711711

712+
def test_futureiter_send_after_throw_no_crash(self):
713+
fut = self._new_future(loop=self.loop)
714+
it = fut.__await__()
715+
next(it)
716+
with self.assertRaises(RuntimeError):
717+
it.throw(RuntimeError)
718+
with self.assertRaises(StopIteration):
719+
it.send(None)
720+
721+
def test_futureiter_send_after_close_no_crash(self):
722+
fut = self._new_future(loop=self.loop)
723+
it = fut.__await__()
724+
next(it)
725+
it.close()
726+
with self.assertRaises(StopIteration):
727+
it.send(None)
728+
729+
712730
@unittest.skipUnless(hasattr(futures, '_CFuture'),
713731
'requires the C _asyncio module')
714732
class CFutureTests(BaseFutureTests, test_utils.TestCase):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a crash in asyncio.Future iterator when send() is
2+
called after throw() or close().

‎Modules/_asynciomodule.c‎

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,10 +1835,9 @@ FutureIter_dealloc(PyObject *it)
18351835
}
18361836

18371837
static PySendResult
1838-
FutureIter_am_send_lock_held(futureiterobject *it, PyObject **result)
1838+
FutureIter_am_send_lock_held(FutureObj *fut, PyObject **result)
18391839
{
18401840
PyObject *res;
1841-
FutureObj *fut = it->future;
18421841
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut);
18431842

18441843
*result = NULL;
@@ -1869,11 +1868,24 @@ FutureIter_am_send(PyObject *op,
18691868
PyObject **result)
18701869
{
18711870
futureiterobject *it = (futureiterobject*)op;
1871+
1872+
FutureObj *fut;
1873+
Py_BEGIN_CRITICAL_SECTION(op);
1874+
fut = (FutureObj*)Py_XNewRef(it->future);
1875+
Py_END_CRITICAL_SECTION();
1876+
1877+
if (fut == NULL) {
1878+
PyErr_SetNone(PyExc_StopIteration);
1879+
*result = NULL;
1880+
return PYGEN_ERROR;
1881+
}
1882+
18721883
/* arg is unused, see the comment on FutureIter_send for clarification */
18731884
PySendResult res;
1874-
Py_BEGIN_CRITICAL_SECTION(it->future);
1875-
res = FutureIter_am_send_lock_held(it, result);
1885+
Py_BEGIN_CRITICAL_SECTION(fut);
1886+
res = FutureIter_am_send_lock_held(fut, result);
18761887
Py_END_CRITICAL_SECTION();
1888+
Py_DECREF(fut);
18771889
return res;
18781890
}
18791891

@@ -1967,7 +1979,9 @@ FutureIter_throw(PyObject *op, PyObject *const *args, Py_ssize_t nargs)
19671979
goto fail;
19681980
}
19691981

1982+
Py_BEGIN_CRITICAL_SECTION(self);
19701983
Py_CLEAR(self->future);
1984+
Py_END_CRITICAL_SECTION();
19711985

19721986
PyErr_Restore(type, val, tb);
19731987

@@ -1980,6 +1994,16 @@ FutureIter_throw(PyObject *op, PyObject *const *args, Py_ssize_t nargs)
19801994
return NULL;
19811995
}
19821996

1997+
static PyObject *
1998+
FutureIter_close(PyObject *self, PyObject *arg)
1999+
{
2000+
futureiterobject *it = (futureiterobject*)self;
2001+
Py_BEGIN_CRITICAL_SECTION(self);
2002+
Py_CLEAR(it->future);
2003+
Py_END_CRITICAL_SECTION();
2004+
Py_RETURN_NONE;
2005+
}
2006+
19832007
static int
19842008
FutureIter_clear(PyObject *op)
19852009
{
@@ -1988,13 +2012,6 @@ FutureIter_clear(PyObject *op)
19882012
return 0;
19892013
}
19902014

1991-
static PyObject *
1992-
FutureIter_close(PyObject *self, PyObject *arg)
1993-
{
1994-
(void)FutureIter_clear(self);
1995-
Py_RETURN_NONE;
1996-
}
1997-
19982015
static int
19992016
FutureIter_traverse(PyObject *op, visitproc visit, void *arg)
20002017
{

0 commit comments

Comments
 (0)