Fix _PyGen_yf()
Issue #28782: Fix a bug in the implementation ``yield from`` when checking
if the next instruction is YIELD_FROM. Regression introduced by WORDCODE
(issue #26647).
Reviewed by Serhiy Storchaka and Yury Selivanov.
diff --git a/Misc/NEWS b/Misc/NEWS
index b606101..929ce53 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,10 @@
Core and Builtins
-----------------
+- Issue #28782: Fix a bug in the implementation ``yield from`` when checking
+ if the next instruction is YIELD_FROM. Regression introduced by WORDCODE
+ (issue #26647).
+
Library
-------
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 558f809..2680ab0 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -355,6 +355,14 @@
PyObject *bytecode = f->f_code->co_code;
unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode);
+ if (f->f_lasti < 0) {
+ /* Return immediately if the frame didn't start yet. YIELD_FROM
+ always come after LOAD_CONST: a code object should not start
+ with YIELD_FROM */
+ assert(code[0] != YIELD_FROM);
+ return NULL;
+ }
+
if (code[f->f_lasti + sizeof(_Py_CODEUNIT)] != YIELD_FROM)
return NULL;
yf = f->f_stacktop[-1];
@@ -463,6 +471,7 @@
assert(ret == yf);
Py_DECREF(ret);
/* Termination repetition of YIELD_FROM */
+ assert(gen->gi_frame->f_lasti >= 0);
gen->gi_frame->f_lasti += sizeof(_Py_CODEUNIT);
if (_PyGen_FetchStopIterationValue(&val) == 0) {
ret = gen_send_ex(gen, val, 0, 0);
diff --git a/Python/ceval.c b/Python/ceval.c
index 83296f6..d5172b9 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2043,6 +2043,7 @@
f->f_stacktop = stack_pointer;
why = WHY_YIELD;
/* and repeat... */
+ assert(f->f_lasti >= (int)sizeof(_Py_CODEUNIT));
f->f_lasti -= sizeof(_Py_CODEUNIT);
goto fast_yield;
}