From 3f57f37fdbe95d566211ca9e856d7d1a2fe15ab8 Mon Sep 17 00:00:00 2001 From: Mikhail Efimov Date: Wed, 11 Jun 2025 20:03:00 +0300 Subject: [PATCH] [3.13] GH-135171: Roll back fix for GH-125038 as it's not suitable for 3.13 --- Lib/test/test_dis.py | 1 - Lib/test/test_generators.py | 21 +++++++++++++-------- Python/bytecodes.c | 27 ++++++++++++++++++++++++--- Python/compile.c | 1 - Python/executor_cases.c.h | 9 ++++++++- Python/generated_cases.c.h | 18 ++++++++++++++++-- 6 files changed, 61 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 73807d7fa95fbd..665e307166d275 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -786,7 +786,6 @@ def foo(x): POP_TOP L1: RESUME 0 LOAD_FAST 0 (.0) - GET_ITER L2: FOR_ITER 10 (to L3) STORE_FAST 1 (z) LOAD_DEREF 2 (x) diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index 515fe7407f1d80..c3cb3fcf0fd478 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -274,21 +274,26 @@ def gen(it): yield x return gen(range(10)) - def process_tests(self, get_generator): + def process_tests(self, get_generator, is_expr): + err_iterator = "'.*' object is not an iterator" + err_iterable = "'.*' object is not iterable" for obj in self.iterables: g_obj = get_generator(obj) with self.subTest(g_obj=g_obj, obj=obj): - self.assertListEqual(list(g_obj), list(obj)) + if is_expr: + self.assertRaisesRegex(TypeError, err_iterator, list, g_obj) + else: + self.assertListEqual(list(g_obj), list(obj)) g_iter = get_generator(iter(obj)) with self.subTest(g_iter=g_iter, obj=obj): self.assertListEqual(list(g_iter), list(obj)) - err_regex = "'.*' object is not iterable" for obj in self.non_iterables: g_obj = get_generator(obj) with self.subTest(g_obj=g_obj): - self.assertRaisesRegex(TypeError, err_regex, list, g_obj) + err = err_iterator if is_expr else err_iterable + self.assertRaisesRegex(TypeError, err, list, g_obj) def test_modify_f_locals(self): def modify_f_locals(g, local, obj): @@ -301,8 +306,8 @@ def get_generator_genexpr(obj): def get_generator_genfunc(obj): return modify_f_locals(self.genfunc(), 'it', obj) - self.process_tests(get_generator_genexpr) - self.process_tests(get_generator_genfunc) + self.process_tests(get_generator_genexpr, True) + self.process_tests(get_generator_genfunc, False) def test_new_gen_from_gi_code(self): def new_gen_from_gi_code(g, obj): @@ -315,8 +320,8 @@ def get_generator_genexpr(obj): def get_generator_genfunc(obj): return new_gen_from_gi_code(self.genfunc(), obj) - self.process_tests(get_generator_genexpr) - self.process_tests(get_generator_genfunc) + self.process_tests(get_generator_genexpr, True) + self.process_tests(get_generator_genfunc, False) class ExceptionTest(unittest.TestCase): diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1da434bbbc892a..bcfc78cf1d45c3 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2599,7 +2599,14 @@ dummy_func( replaced op(_FOR_ITER, (iter -- iter, next)) { /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ - next = (*Py_TYPE(iter)->tp_iternext)(iter); + iternextfunc func = Py_TYPE(iter)->tp_iternext; + if (func == NULL) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.100s' object is not an iterator", + Py_TYPE(iter)->tp_name); + ERROR_NO_POP(); + } + next = func(iter); if (next == NULL) { if (_PyErr_Occurred(tstate)) { if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { @@ -2622,7 +2629,14 @@ dummy_func( op(_FOR_ITER_TIER_TWO, (iter -- iter, next)) { /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ - next = (*Py_TYPE(iter)->tp_iternext)(iter); + iternextfunc func = Py_TYPE(iter)->tp_iternext; + if (func == NULL) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.100s' object is not an iterator", + Py_TYPE(iter)->tp_name); + ERROR_NO_POP(); + } + next = func(iter); if (next == NULL) { if (_PyErr_Occurred(tstate)) { if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { @@ -2643,7 +2657,14 @@ dummy_func( inst(INSTRUMENTED_FOR_ITER, (unused/1 -- )) { _Py_CODEUNIT *target; PyObject *iter = TOP(); - PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); + iternextfunc func = Py_TYPE(iter)->tp_iternext; + if (func == NULL) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.100s' object is not an iterator", + Py_TYPE(iter)->tp_name); + ERROR_NO_POP(); + } + PyObject *next = func(iter); if (next != NULL) { PUSH(next); target = next_instr; diff --git a/Python/compile.c b/Python/compile.c index bb2c2293a38c9a..15dcbb5eba58bf 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5407,7 +5407,6 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc, if (IS_LABEL(start)) { depth++; - ADDOP(c, LOC(gen->iter), GET_ITER); USE_LABEL(c, start); ADDOP_JUMP(c, LOC(gen->iter), FOR_ITER, anchor); } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 1bfbeb675b1b6f..a5cbadadd23f22 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2629,7 +2629,14 @@ PyObject *next; iter = stack_pointer[-1]; /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ - next = (*Py_TYPE(iter)->tp_iternext)(iter); + iternextfunc func = Py_TYPE(iter)->tp_iternext; + if (func == NULL) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.100s' object is not an iterator", + Py_TYPE(iter)->tp_name); + JUMP_TO_ERROR(); + } + next = func(iter); if (next == NULL) { if (_PyErr_Occurred(tstate)) { if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index be00bf6eb6a39e..0f3f9f8fcfc489 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2787,7 +2787,14 @@ // _FOR_ITER { /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ - next = (*Py_TYPE(iter)->tp_iternext)(iter); + iternextfunc func = Py_TYPE(iter)->tp_iternext; + if (func == NULL) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.100s' object is not an iterator", + Py_TYPE(iter)->tp_name); + goto error; + } + next = func(iter); if (next == NULL) { if (_PyErr_Occurred(tstate)) { if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { @@ -3303,7 +3310,14 @@ /* Skip 1 cache entry */ _Py_CODEUNIT *target; PyObject *iter = TOP(); - PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); + iternextfunc func = Py_TYPE(iter)->tp_iternext; + if (func == NULL) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.100s' object is not an iterator", + Py_TYPE(iter)->tp_name); + goto error; + } + PyObject *next = func(iter); if (next != NULL) { PUSH(next); target = next_instr;