From 1371295e678f00a7c89dc5bb2ab61ede9adbc094 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Tue, 5 Nov 2024 04:56:36 -0500 Subject: [PATCH] gh-126366: Fix crash if `__iter__` raises an exception during `yield from` (#126369) --- Lib/test/test_yield_from.py | 13 +++++++++++++ .../2024-11-03-15-15-36.gh-issue-126366.8BBdGU.rst | 2 ++ Python/bytecodes.c | 5 +++-- Python/executor_cases.c.h | 5 +++-- Python/generated_cases.c.h | 5 +++-- Tools/jit/ignore-tests-emulated-linux.txt | 1 + 6 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-11-03-15-15-36.gh-issue-126366.8BBdGU.rst diff --git a/Lib/test/test_yield_from.py b/Lib/test/test_yield_from.py index 1a60357a1bc..b90e15e2002 100644 --- a/Lib/test/test_yield_from.py +++ b/Lib/test/test_yield_from.py @@ -1576,6 +1576,19 @@ class TestInterestingEdgeCases(unittest.TestCase): self.assertIsNone(caught.exception.__context__) self.assert_stop_iteration(g) + def test_throws_in_iter(self): + # See GH-126366: NULL pointer dereference if __iter__ + # threw an exception. + class Silly: + def __iter__(self): + raise RuntimeError("nobody expects the spanish inquisition") + + def my_generator(): + yield from Silly() + + with self.assertRaisesRegex(RuntimeError, "nobody expects the spanish inquisition"): + next(iter(my_generator())) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-11-03-15-15-36.gh-issue-126366.8BBdGU.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-11-03-15-15-36.gh-issue-126366.8BBdGU.rst new file mode 100644 index 00000000000..a47233602e4 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-11-03-15-15-36.gh-issue-126366.8BBdGU.rst @@ -0,0 +1,2 @@ +Fix crash when using ``yield from`` on an object that raises an exception in +its ``__iter__``. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 81b527e8c05..8c52db6ab68 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2811,11 +2811,12 @@ dummy_func( } else { /* `iterable` is not a generator. */ - iter = PyStackRef_FromPyObjectSteal(PyObject_GetIter(iterable_o)); + PyObject *iter_o = PyObject_GetIter(iterable_o); DEAD(iterable); - if (PyStackRef_IsNull(iter)) { + if (iter_o == NULL) { ERROR_NO_POP(); } + iter = PyStackRef_FromPyObjectSteal(iter_o); DECREF_INPUTS(); } } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 9fac4e881b8..1d63402214d 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3437,11 +3437,12 @@ else { /* `iterable` is not a generator. */ _PyFrame_SetStackPointer(frame, stack_pointer); - iter = PyStackRef_FromPyObjectSteal(PyObject_GetIter(iterable_o)); + PyObject *iter_o = PyObject_GetIter(iterable_o); stack_pointer = _PyFrame_GetStackPointer(frame); - if (PyStackRef_IsNull(iter)) { + if (iter_o == NULL) { JUMP_TO_ERROR(); } + iter = PyStackRef_FromPyObjectSteal(iter_o); PyStackRef_CLOSE(iterable); } } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index c6b8fbc50f3..d346875ea44 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4304,11 +4304,12 @@ else { /* `iterable` is not a generator. */ _PyFrame_SetStackPointer(frame, stack_pointer); - iter = PyStackRef_FromPyObjectSteal(PyObject_GetIter(iterable_o)); + PyObject *iter_o = PyObject_GetIter(iterable_o); stack_pointer = _PyFrame_GetStackPointer(frame); - if (PyStackRef_IsNull(iter)) { + if (iter_o == NULL) { goto error; } + iter = PyStackRef_FromPyObjectSteal(iter_o); PyStackRef_CLOSE(iterable); } } diff --git a/Tools/jit/ignore-tests-emulated-linux.txt b/Tools/jit/ignore-tests-emulated-linux.txt index e379e39def0..080a5695744 100644 --- a/Tools/jit/ignore-tests-emulated-linux.txt +++ b/Tools/jit/ignore-tests-emulated-linux.txt @@ -71,6 +71,7 @@ test.test_socket.RecvmsgSCMRightsStreamTest.testCmsgTruncLen1 test.test_socket.RecvmsgSCMRightsStreamTest.testCmsgTruncLen2Minus1 test.test_subprocess.POSIXProcessTestCase.test_exception_bad_args_0 test.test_subprocess.POSIXProcessTestCase.test_exception_bad_executable +test.test_subprocess.POSIXProcessTestCase.test_vfork_used_when_expected test.test_subprocess.ProcessTestCase.test_cwd_with_relative_arg test.test_subprocess.ProcessTestCase.test_cwd_with_relative_executable test.test_subprocess.ProcessTestCase.test_empty_env