From a7b77bd9317de98f06d2f424a530b57bcde94b93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 13 Jan 2025 16:54:13 +0100 Subject: [PATCH] gh-128078: Use `PyErr_SetRaisedException` in `_PyGen_SetStopIterationValue` (GH-128287) (cherry picked from commit 402b91da87052878b4e7e8946ba91bdf4ee4bebe) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Kumar Aditya --- Lib/test/test_asyncgen.py | 2 +- Objects/genobject.c | 32 ++++++++++---------------------- 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py index 16164492b25690..951c5502803789 100644 --- a/Lib/test/test_asyncgen.py +++ b/Lib/test/test_asyncgen.py @@ -1165,7 +1165,7 @@ async def run(): with self.assertRaises(StopAsyncIteration): await it.__anext__() res = await anext(it, ('a', 'b')) - self.assertEqual(res, ('a', 'b')) + self.assertTupleEqual(res, ('a', 'b')) self.loop.run_until_complete(run()) diff --git a/Objects/genobject.c b/Objects/genobject.c index 524cda1487813c..3a9af4d4c182a3 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -605,30 +605,18 @@ int _PyGen_SetStopIterationValue(PyObject *value) { assert(!PyErr_Occurred()); - PyObject *e; - - if (value == NULL || - (!PyTuple_Check(value) && !PyExceptionInstance_Check(value))) - { - /* Delay exception instantiation if we can */ - PyErr_SetObject(PyExc_StopIteration, value); - return 0; - } - /* Construct an exception instance manually with - * PyObject_CallOneArg and pass it to PyErr_SetObject. - * - * We do this to handle a situation when "value" is a tuple, in which - * case PyErr_SetObject would set the value of StopIteration to - * the first element of the tuple. - * - * (See PyErr_SetObject/_PyErr_CreateException code for details.) - */ - e = PyObject_CallOneArg(PyExc_StopIteration, value); - if (e == NULL) { + // Construct an exception instance manually with PyObject_CallOneArg() + // but use PyErr_SetRaisedException() instead of PyErr_SetObject() as + // PyErr_SetObject(exc_type, value) has a fast path when 'value' + // is a tuple, where the value of the StopIteration exception would be + // set to 'value[0]' instead of 'value'. + PyObject *exc = value == NULL + ? PyObject_CallNoArgs(PyExc_StopIteration) + : PyObject_CallOneArg(PyExc_StopIteration, value); + if (exc == NULL) { return -1; } - PyErr_SetObject(PyExc_StopIteration, e); - Py_DECREF(e); + PyErr_SetRaisedException(exc /* stolen */); return 0; }