diff options
author | Mark Shannon <mark@hotpy.org> | 2021-12-08 14:46:32 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-08 14:46:32 (GMT) |
commit | 99c72326d245fb604609a87a51ef1ad0845467b7 (patch) | |
tree | 62317e0c33adb14af339a75d924365c2957ba8c3 | |
parent | cca3004f64d49c9e170396ac787712fe03bffb29 (diff) | |
download | cpython-99c72326d245fb604609a87a51ef1ad0845467b7.zip cpython-99c72326d245fb604609a87a51ef1ad0845467b7.tar.gz cpython-99c72326d245fb604609a87a51ef1ad0845467b7.tar.bz2 |
[3.10] bpo-46009: Do not exhaust generator when send() method raises (GH-29986). (GH-29988)
* [3.10] bpo-46009: Do not exhaust generator when send() method raises (GH-29986).
(cherry picked from commit 69806b9516dbe092381f3ef884c7c64bb9b8414a)
Co-authored-by: Mark Shannon <mark@hotpy.org>
* Rename variable after cherry-pick.
* Add NULL check.
-rw-r--r-- | Doc/library/dis.rst | 5 | ||||
-rw-r--r-- | Lib/test/test_generators.py | 8 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2021-12-08-11-06-53.bpo-46009.cL8pH0.rst | 5 | ||||
-rw-r--r-- | Objects/genobject.c | 13 | ||||
-rw-r--r-- | Python/ceval.c | 20 |
5 files changed, 30 insertions, 21 deletions
diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index e7e67da..74820f9 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1252,9 +1252,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 diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index d14c757..3bf5f3b 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -161,6 +161,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 index 0000000..a80e66b --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-12-08-11-06-53.bpo-46009.cL8pH0.rst @@ -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. diff --git a/Objects/genobject.c b/Objects/genobject.c index 3ac38de..33fc4a5 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -145,6 +145,19 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, PyObject *result; *presult = NULL; + if (f != NULL && f->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 (f != NULL && _PyFrame_IsExecuting(f)) { const char *msg = "generator already executing"; if (PyCoro_CheckExact(gen)) { diff --git a/Python/ceval.c b/Python/ceval.c index 624baf5..8ad1713 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2649,25 +2649,9 @@ main_loop: case 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(); } |