Skip to content

Commit 84af903

Browse files
authored
bpo-28963: Fix out of bound iteration in asyncio.Future.remove_done_callback/C (#408)
1 parent 2f15645 commit 84af903

File tree

3 files changed

+33
-1
lines changed

3 files changed

+33
-1
lines changed

Lib/test/test_asyncio/test_futures.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,35 @@ def test_remove_done_callback(self):
569569
self.assertEqual(bag, [2])
570570
self.assertEqual(f.result(), 'foo')
571571

572+
def test_remove_done_callbacks_list_mutation(self):
573+
# see http://bugs.python.org/issue28963 for details
574+
575+
fut = self._new_future()
576+
fut.add_done_callback(str)
577+
578+
for _ in range(63):
579+
fut.add_done_callback(id)
580+
581+
class evil:
582+
def __eq__(self, other):
583+
fut.remove_done_callback(id)
584+
return False
585+
586+
fut.remove_done_callback(evil())
587+
588+
def test_schedule_callbacks_list_mutation(self):
589+
# see http://bugs.python.org/issue28963 for details
590+
591+
def mut(f):
592+
f.remove_done_callback(str)
593+
594+
fut = self._new_future()
595+
fut.add_done_callback(mut)
596+
fut.add_done_callback(str)
597+
fut.add_done_callback(str)
598+
fut.set_result(1)
599+
test_utils.run_briefly(self.loop)
600+
572601

573602
@unittest.skipUnless(hasattr(futures, '_CFuture'),
574603
'requires the C _asyncio module')

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,9 @@ Extension Modules
259259
Library
260260
-------
261261

262+
- bpo-28963: Fix out of bound iteration in asyncio.Future.remove_done_callback
263+
implemented in C.
264+
262265
- bpo-29704: asyncio.subprocess.SubprocessStreamProtocol no longer closes before
263266
all pipes are closed.
264267

Modules/_asynciomodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ _asyncio_Future_remove_done_callback(FutureObj *self, PyObject *fn)
522522
return NULL;
523523
}
524524

525-
for (i = 0; i < len; i++) {
525+
for (i = 0; i < PyList_GET_SIZE(self->fut_callbacks); i++) {
526526
int ret;
527527
PyObject *item = PyList_GET_ITEM(self->fut_callbacks, i);
528528

0 commit comments

Comments
 (0)