Skip to content

Commit 320a73f

Browse files
[3.15] gh-146065: Fix NULL dereference in FutureIter_am_send (GH-158468) (#159870)
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 d4a6bcb commit 320a73f

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
@@ -763,6 +763,24 @@ def test_future_disallow_multiple_initialization(self):
763763
with self.assertRaises(RuntimeError, msg="is already initialized"):
764764
f.__init__(loop=self.loop)
765765

766+
def test_futureiter_send_after_throw_no_crash(self):
767+
fut = self._new_future(loop=self.loop)
768+
it = fut.__await__()
769+
next(it)
770+
with self.assertRaises(RuntimeError):
771+
it.throw(RuntimeError)
772+
with self.assertRaises(StopIteration):
773+
it.send(None)
774+
775+
def test_futureiter_send_after_close_no_crash(self):
776+
fut = self._new_future(loop=self.loop)
777+
it = fut.__await__()
778+
next(it)
779+
it.close()
780+
with self.assertRaises(StopIteration):
781+
it.send(None)
782+
783+
766784
@unittest.skipUnless(hasattr(futures, '_CFuture'),
767785
'requires the C _asyncio module')
768786
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
@@ -1822,10 +1822,9 @@ FutureIter_dealloc(PyObject *it)
18221822
}
18231823

18241824
static PySendResult
1825-
FutureIter_am_send_lock_held(futureiterobject *it, PyObject **result)
1825+
FutureIter_am_send_lock_held(FutureObj *fut, PyObject **result)
18261826
{
18271827
PyObject *res;
1828-
FutureObj *fut = it->future;
18291828
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut);
18301829

18311830
*result = NULL;
@@ -1856,11 +1855,24 @@ FutureIter_am_send(PyObject *op,
18561855
PyObject **result)
18571856
{
18581857
futureiterobject *it = (futureiterobject*)op;
1858+
1859+
FutureObj *fut;
1860+
Py_BEGIN_CRITICAL_SECTION(op);
1861+
fut = (FutureObj*)Py_XNewRef(it->future);
1862+
Py_END_CRITICAL_SECTION();
1863+
1864+
if (fut == NULL) {
1865+
PyErr_SetNone(PyExc_StopIteration);
1866+
*result = NULL;
1867+
return PYGEN_ERROR;
1868+
}
1869+
18591870
/* arg is unused, see the comment on FutureIter_send for clarification */
18601871
PySendResult res;
1861-
Py_BEGIN_CRITICAL_SECTION(it->future);
1862-
res = FutureIter_am_send_lock_held(it, result);
1872+
Py_BEGIN_CRITICAL_SECTION(fut);
1873+
res = FutureIter_am_send_lock_held(fut, result);
18631874
Py_END_CRITICAL_SECTION();
1875+
Py_DECREF(fut);
18641876
return res;
18651877
}
18661878

@@ -1954,7 +1966,9 @@ FutureIter_throw(PyObject *op, PyObject *const *args, Py_ssize_t nargs)
19541966
goto fail;
19551967
}
19561968

1969+
Py_BEGIN_CRITICAL_SECTION(self);
19571970
Py_CLEAR(self->future);
1971+
Py_END_CRITICAL_SECTION();
19581972

19591973
PyErr_Restore(type, val, tb);
19601974

@@ -1967,6 +1981,16 @@ FutureIter_throw(PyObject *op, PyObject *const *args, Py_ssize_t nargs)
19671981
return NULL;
19681982
}
19691983

1984+
static PyObject *
1985+
FutureIter_close(PyObject *self, PyObject *arg)
1986+
{
1987+
futureiterobject *it = (futureiterobject*)self;
1988+
Py_BEGIN_CRITICAL_SECTION(self);
1989+
Py_CLEAR(it->future);
1990+
Py_END_CRITICAL_SECTION();
1991+
Py_RETURN_NONE;
1992+
}
1993+
19701994
static int
19711995
FutureIter_clear(PyObject *op)
19721996
{
@@ -1975,13 +1999,6 @@ FutureIter_clear(PyObject *op)
19751999
return 0;
19762000
}
19772001

1978-
static PyObject *
1979-
FutureIter_close(PyObject *self, PyObject *arg)
1980-
{
1981-
(void)FutureIter_clear(self);
1982-
Py_RETURN_NONE;
1983-
}
1984-
19852002
static int
19862003
FutureIter_traverse(PyObject *op, visitproc visit, void *arg)
19872004
{

0 commit comments

Comments
 (0)