summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2021-12-08 12:09:26 (GMT)
committerGitHub <noreply@github.com>2021-12-08 12:09:26 (GMT)
commit69806b9516dbe092381f3ef884c7c64bb9b8414a (patch)
tree475262014715b235fa9a122ff09c973d47536f8e
parent3e0f13b9e48eec8c54a185e4180bfca4e5e685f6 (diff)
downloadcpython-69806b9516dbe092381f3ef884c7c64bb9b8414a.zip
cpython-69806b9516dbe092381f3ef884c7c64bb9b8414a.tar.gz
cpython-69806b9516dbe092381f3ef884c7c64bb9b8414a.tar.bz2
bpo-46009: Do not exhaust generator when send() method raises (GH-29986)
-rw-r--r--Doc/library/dis.rst5
-rw-r--r--Lib/test/test_generators.py8
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2021-12-08-11-06-53.bpo-46009.cL8pH0.rst5
-rw-r--r--Objects/genobject.c13
-rw-r--r--Python/ceval.c20
5 files changed, 30 insertions, 21 deletions
diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
index 62d2150..9665e8d 100644
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -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
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py
index 433204b..4f4fd9c 100644
--- a/Lib/test/test_generators.py
+++ b/Lib/test/test_generators.py
@@ -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
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 c4ba660..147194c 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -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)) {
diff --git a/Python/ceval.c b/Python/ceval.c
index 2e40c0f..4f5ccf5 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -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();
}