]> granicus.if.org Git - python/commitdiff
bpo-30828: Fix out of bounds write in `asyncio.CFuture.remove_done_callback() (#2569)
authorYury Selivanov <yury@magic.io>
Wed, 5 Jul 2017 17:32:03 +0000 (13:32 -0400)
committerGitHub <noreply@github.com>
Wed, 5 Jul 2017 17:32:03 +0000 (13:32 -0400)
Lib/test/test_asyncio/test_futures.py
Misc/NEWS.d/next/Library/2017-07-04-13-10-52.bpo-30828.CLvEvV.rst [new file with mode: 0644]
Modules/_asynciomodule.c

index 5d4b2d2aa0efc0b73ec266389a5823dab91c820d..ce657fc1b6a058e321deb77a69dfbb437f3403a4 100644 (file)
@@ -593,7 +593,7 @@ class BaseFutureDoneCallbackTests():
 
         fut.remove_done_callback(evil())
 
-    def test_schedule_callbacks_list_mutation(self):
+    def test_schedule_callbacks_list_mutation_1(self):
         # see http://bugs.python.org/issue28963 for details
 
         def mut(f):
@@ -606,6 +606,28 @@ class BaseFutureDoneCallbackTests():
         fut.set_result(1)
         test_utils.run_briefly(self.loop)
 
+    def test_schedule_callbacks_list_mutation_2(self):
+        # see http://bugs.python.org/issue30828 for details
+
+        fut = self._new_future()
+        fut.add_done_callback(str)
+
+        for _ in range(63):
+            fut.add_done_callback(id)
+
+        max_extra_cbs = 100
+        extra_cbs = 0
+
+        class evil:
+            def __eq__(self, other):
+                nonlocal extra_cbs
+                extra_cbs += 1
+                if extra_cbs < max_extra_cbs:
+                    fut.add_done_callback(id)
+                return False
+
+        fut.remove_done_callback(evil())
+
 
 @unittest.skipUnless(hasattr(futures, '_CFuture'),
                      'requires the C _asyncio module')
diff --git a/Misc/NEWS.d/next/Library/2017-07-04-13-10-52.bpo-30828.CLvEvV.rst b/Misc/NEWS.d/next/Library/2017-07-04-13-10-52.bpo-30828.CLvEvV.rst
new file mode 100644 (file)
index 0000000..8924962
--- /dev/null
@@ -0,0 +1 @@
+Fix out of bounds write in `asyncio.CFuture.remove_done_callback()`.
index b8a88e61d4aba45fac501158e66cc6bb4b6cee32..b998a04e623cad100c6179f3b81fe3e550a556e0 100644 (file)
@@ -532,9 +532,16 @@ _asyncio_Future_remove_done_callback(FutureObj *self, PyObject *fn)
             goto fail;
         }
         if (ret == 0) {
-            Py_INCREF(item);
-            PyList_SET_ITEM(newlist, j, item);
-            j++;
+            if (j < len) {
+                Py_INCREF(item);
+                PyList_SET_ITEM(newlist, j, item);
+                j++;
+            }
+            else {
+                if (PyList_Append(newlist, item)) {
+                    goto fail;
+                }
+            }
         }
     }