Skip to content

Commit aaa4f99

Browse files
authored
[3.6] bpo-30828: Fix out of bounds write in `asyncio.CFuture.remove_done_callback() (GH-2569) (#2590)
(cherry picked from commit 833a3b0)
1 parent e3a0ff0 commit aaa4f99

File tree

3 files changed

+34
-4
lines changed

3 files changed

+34
-4
lines changed

‎Lib/test/test_asyncio/test_futures.py‎

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ def __eq__(self, other):
593593

594594
fut.remove_done_callback(evil())
595595

596-
def test_schedule_callbacks_list_mutation(self):
596+
def test_schedule_callbacks_list_mutation_1(self):
597597
# see http://bugs.python.org/issue28963 for details
598598

599599
def mut(f):
@@ -606,6 +606,28 @@ def mut(f):
606606
fut.set_result(1)
607607
test_utils.run_briefly(self.loop)
608608

609+
def test_schedule_callbacks_list_mutation_2(self):
610+
# see http://bugs.python.org/issue30828 for details
611+
612+
fut = self._new_future()
613+
fut.add_done_callback(str)
614+
615+
for _ in range(63):
616+
fut.add_done_callback(id)
617+
618+
max_extra_cbs = 100
619+
extra_cbs = 0
620+
621+
class evil:
622+
def __eq__(self, other):
623+
nonlocal extra_cbs
624+
extra_cbs += 1
625+
if extra_cbs < max_extra_cbs:
626+
fut.add_done_callback(id)
627+
return False
628+
629+
fut.remove_done_callback(evil())
630+
609631

610632
@unittest.skipUnless(hasattr(futures, '_CFuture'),
611633
'requires the C _asyncio module')
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix out of bounds write in `asyncio.CFuture.remove_done_callback()`.

‎Modules/_asynciomodule.c‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -531,9 +531,16 @@ _asyncio_Future_remove_done_callback(FutureObj *self, PyObject *fn)
531531
goto fail;
532532
}
533533
if (ret == 0) {
534-
Py_INCREF(item);
535-
PyList_SET_ITEM(newlist, j, item);
536-
j++;
534+
if (j < len) {
535+
Py_INCREF(item);
536+
PyList_SET_ITEM(newlist, j, item);
537+
j++;
538+
}
539+
else {
540+
if (PyList_Append(newlist, item)) {
541+
goto fail;
542+
}
543+
}
537544
}
538545
}
539546

0 commit comments

Comments
 (0)