]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-46009: Do not exhaust generator when send() method raises (GH-29986)
authorMark Shannon <mark@hotpy.org>
Wed, 8 Dec 2021 12:09:26 +0000 (12:09 +0000)
committerGitHub <noreply@github.com>
Wed, 8 Dec 2021 12:09:26 +0000 (12:09 +0000)
Doc/library/dis.rst
Lib/test/test_generators.py
Misc/NEWS.d/next/Core and Builtins/2021-12-08-11-06-53.bpo-46009.cL8pH0.rst [new file with mode: 0644]
Objects/genobject.c
Python/ceval.c

index 62d2150e304faba161ab3af783073f7c2d29bebd..9665e8dbf6cfc6516463dc952fe0ca0249fcbb79 100644 (file)
@@ -1170,9 +1170,8 @@ All of the following opcodes use their arguments.
 
 .. opcode:: GEN_START (kind)
 
-    Pops TOS. If TOS was not ``None``, raises an exception. The ``kind``
-    operand corresponds to the type of generator or coroutine and determines
-    the error message. The legal kinds are 0 for generator, 1 for coroutine,
+    Pops TOS. The ``kind`` operand corresponds to the type of generator or
+    coroutine. The legal kinds are 0 for generator, 1 for coroutine,
     and 2 for async generator.
 
    .. versionadded:: 3.10
index 433204b09fee65af0486588372726e74a2c6f1b9..4f4fd9c5aa76ed8806a7f87cfa93a2dbd9f6e019 100644 (file)
@@ -162,6 +162,14 @@ class GeneratorTest(unittest.TestCase):
             with self.assertRaises((TypeError, pickle.PicklingError)):
                 pickle.dumps(g, proto)
 
+    def test_send_non_none_to_new_gen(self):
+        def f():
+            yield 1
+        g = f()
+        with self.assertRaises(TypeError):
+            g.send(0)
+        self.assertEqual(next(g), 1)
+
 
 class ExceptionTest(unittest.TestCase):
     # Tests for the issue #23353: check that the currently handled exception
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-12-08-11-06-53.bpo-46009.cL8pH0.rst b/Misc/NEWS.d/next/Core and Builtins/2021-12-08-11-06-53.bpo-46009.cL8pH0.rst
new file mode 100644 (file)
index 0000000..a80e66b
--- /dev/null
@@ -0,0 +1,5 @@
+Restore behavior from 3.9 and earlier when sending non-None to newly started
+generator. In 3.9 this did not affect the state of the generator. In 3.10.0
+and 3.10.1 ``gen_func().send(0)`` is equivalent to
+``gen_func().throw(TypeError(...)`` which exhausts the generator. In 3.10.2
+onward, the behavior has been reverted to that of 3.9.
index c4ba660530cae67352bf3874fc74423f2f2238ce..147194c38a0a1db82c0dab9a8a9796f5d48c5f6b 100644 (file)
@@ -157,6 +157,19 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
     PyObject *result;
 
     *presult = NULL;
+    if (frame->f_lasti < 0 && arg && arg != Py_None) {
+        const char *msg = "can't send non-None value to a "
+                            "just-started generator";
+        if (PyCoro_CheckExact(gen)) {
+            msg = NON_INIT_CORO_MSG;
+        }
+        else if (PyAsyncGen_CheckExact(gen)) {
+            msg = "can't send non-None value to a "
+                    "just-started async generator";
+        }
+        PyErr_SetString(PyExc_TypeError, msg);
+        return PYGEN_ERROR;
+    }
     if (gen->gi_frame_valid && _PyFrame_IsExecuting(frame)) {
         const char *msg = "generator already executing";
         if (PyCoro_CheckExact(gen)) {
index 2e40c0f5b391ae46bd4741f838182fe06efa1f27..4f5ccf51e9cfe742f14bf994a273e56f2e004628 100644 (file)
@@ -2714,25 +2714,9 @@ check_eval_breaker:
 
         TARGET(GEN_START) {
             PyObject *none = POP();
+            assert(none == Py_None);
+            assert(oparg < 3);
             Py_DECREF(none);
-            if (!Py_IsNone(none)) {
-                if (oparg > 2) {
-                    _PyErr_SetString(tstate, PyExc_SystemError,
-                        "Illegal kind for GEN_START");
-                }
-                else {
-                    static const char *gen_kind[3] = {
-                        "generator",
-                        "coroutine",
-                        "async generator"
-                    };
-                    _PyErr_Format(tstate, PyExc_TypeError,
-                        "can't send non-None value to a "
-                                "just-started %s",
-                                gen_kind[oparg]);
-                }
-                goto error;
-            }
             DISPATCH();
         }