]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-39386: Prevent double awaiting of async iterator (GH-18081)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Mon, 20 Jan 2020 23:07:54 +0000 (15:07 -0800)
committerGitHub <noreply@github.com>
Mon, 20 Jan 2020 23:07:54 +0000 (15:07 -0800)
(cherry picked from commit a96e06db77dcbd3433d39761ddb4615d7d96284a)

Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
Lib/test/test_asyncgen.py
Misc/NEWS.d/next/Core and Builtins/2020-01-20-21-40-57.bpo-39386.ULqD8t.rst [new file with mode: 0644]
Objects/genobject.c

index cca6d58417ac4c9a2b1c2bbb5602586546d0f6e7..426d5d1161423a7a3d4bf59cbfaa8af95c6940ae 100644 (file)
@@ -1117,6 +1117,42 @@ class AsyncGenAsyncioTest(unittest.TestCase):
 
         self.assertEqual([], messages)
 
+    def test_async_gen_await_anext_twice(self):
+        async def async_iterate():
+            yield 1
+            yield 2
+
+        async def run():
+            it = async_iterate()
+            nxt = it.__anext__()
+            await nxt
+            with self.assertRaisesRegex(
+                    RuntimeError,
+                    r"cannot reuse already awaited __anext__\(\)/asend\(\)"
+            ):
+                await nxt
+
+            await it.aclose()  # prevent unfinished iterator warning
+
+        self.loop.run_until_complete(run())
+
+    def test_async_gen_await_aclose_twice(self):
+        async def async_iterate():
+            yield 1
+            yield 2
+
+        async def run():
+            it = async_iterate()
+            nxt = it.aclose()
+            await nxt
+            with self.assertRaisesRegex(
+                    RuntimeError,
+                    r"cannot reuse already awaited aclose\(\)/athrow\(\)"
+            ):
+                await nxt
+
+        self.loop.run_until_complete(run())
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-01-20-21-40-57.bpo-39386.ULqD8t.rst b/Misc/NEWS.d/next/Core and Builtins/2020-01-20-21-40-57.bpo-39386.ULqD8t.rst
new file mode 100644 (file)
index 0000000..f24e1f4
--- /dev/null
@@ -0,0 +1 @@
+Prevent double awaiting of async iterator.
index 7fc7a1f2aeb3d2f07a4de8041408ba0269779bdf..a42169f82e4d73452d5cba3372ba08aae23b2f5e 100644 (file)
@@ -1533,7 +1533,9 @@ async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg)
     PyObject *result;
 
     if (o->ags_state == AWAITABLE_STATE_CLOSED) {
-        PyErr_SetNone(PyExc_StopIteration);
+        PyErr_SetString(
+            PyExc_RuntimeError,
+            "cannot reuse already awaited __anext__()/asend()");
         return NULL;
     }
 
@@ -1568,7 +1570,9 @@ async_gen_asend_throw(PyAsyncGenASend *o, PyObject *args)
     PyObject *result;
 
     if (o->ags_state == AWAITABLE_STATE_CLOSED) {
-        PyErr_SetNone(PyExc_StopIteration);
+        PyErr_SetString(
+            PyExc_RuntimeError,
+            "cannot reuse already awaited __anext__()/asend()");
         return NULL;
     }
 
@@ -1802,7 +1806,9 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
 
     if (f == NULL || f->f_stacktop == NULL ||
             o->agt_state == AWAITABLE_STATE_CLOSED) {
-        PyErr_SetNone(PyExc_StopIteration);
+        PyErr_SetString(
+            PyExc_RuntimeError,
+            "cannot reuse already awaited aclose()/athrow()");
         return NULL;
     }
 
@@ -1906,7 +1912,9 @@ async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *args)
     PyObject *retval;
 
     if (o->agt_state == AWAITABLE_STATE_CLOSED) {
-        PyErr_SetNone(PyExc_StopIteration);
+        PyErr_SetString(
+            PyExc_RuntimeError,
+            "cannot reuse already awaited aclose()/athrow()");
         return NULL;
     }