mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
Issue #23996: Added _PyGen_SetStopIterationValue for safe raising
StopIteration with value. More safely handle non-normalized exceptions in -_PyGen_FetchStopIterationValue.
This commit is contained in:
parent
04b3d8b697
commit
24411f8a8d
4 changed files with 133 additions and 10 deletions
|
@ -154,12 +154,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
|
|||
/* Delay exception instantiation if we can */
|
||||
PyErr_SetNone(PyExc_StopIteration);
|
||||
} else {
|
||||
PyObject *e = PyObject_CallFunctionObjArgs(
|
||||
PyExc_StopIteration, result, NULL);
|
||||
if (e != NULL) {
|
||||
PyErr_SetObject(PyExc_StopIteration, e);
|
||||
Py_DECREF(e);
|
||||
}
|
||||
_PyGen_SetStopIterationValue(result);
|
||||
}
|
||||
Py_CLEAR(result);
|
||||
}
|
||||
|
@ -459,6 +454,43 @@ gen_iternext(PyGenObject *gen)
|
|||
return gen_send_ex(gen, NULL, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set StopIteration with specified value. Value can be arbitrary object
|
||||
* or NULL.
|
||||
*
|
||||
* Returns 0 if StopIteration is set and -1 if any other exception is set.
|
||||
*/
|
||||
int
|
||||
_PyGen_SetStopIterationValue(PyObject *value)
|
||||
{
|
||||
PyObject *e;
|
||||
|
||||
if (value == NULL ||
|
||||
(!PyTuple_Check(value) &&
|
||||
!PyObject_TypeCheck(value, (PyTypeObject *) PyExc_StopIteration)))
|
||||
{
|
||||
/* Delay exception instantiation if we can */
|
||||
PyErr_SetObject(PyExc_StopIteration, value);
|
||||
return 0;
|
||||
}
|
||||
/* Construct an exception instance manually with
|
||||
* PyObject_CallFunctionObjArgs 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_CallFunctionObjArgs(PyExc_StopIteration, value, NULL);
|
||||
if (e == NULL) {
|
||||
return -1;
|
||||
}
|
||||
PyErr_SetObject(PyExc_StopIteration, e);
|
||||
Py_DECREF(e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If StopIteration exception is set, fetches its 'value'
|
||||
* attribute if any, otherwise sets pvalue to None.
|
||||
|
@ -469,7 +501,8 @@ gen_iternext(PyGenObject *gen)
|
|||
*/
|
||||
|
||||
int
|
||||
_PyGen_FetchStopIterationValue(PyObject **pvalue) {
|
||||
_PyGen_FetchStopIterationValue(PyObject **pvalue)
|
||||
{
|
||||
PyObject *et, *ev, *tb;
|
||||
PyObject *value = NULL;
|
||||
|
||||
|
@ -481,8 +514,15 @@ _PyGen_FetchStopIterationValue(PyObject **pvalue) {
|
|||
value = ((PyStopIterationObject *)ev)->value;
|
||||
Py_INCREF(value);
|
||||
Py_DECREF(ev);
|
||||
} else if (et == PyExc_StopIteration) {
|
||||
/* avoid normalisation and take ev as value */
|
||||
} else if (et == PyExc_StopIteration && !PyTuple_Check(ev)) {
|
||||
/* Avoid normalisation and take ev as value.
|
||||
*
|
||||
* Normalization is required if the value is a tuple, in
|
||||
* that case the value of StopIteration would be set to
|
||||
* the first element of the tuple.
|
||||
*
|
||||
* (See _PyErr_CreateException code for details.)
|
||||
*/
|
||||
value = ev;
|
||||
} else {
|
||||
/* normalisation required */
|
||||
|
@ -1012,7 +1052,7 @@ typedef struct {
|
|||
static PyObject *
|
||||
aiter_wrapper_iternext(PyAIterWrapper *aw)
|
||||
{
|
||||
PyErr_SetObject(PyExc_StopIteration, aw->aw_aiter);
|
||||
_PyGen_SetStopIterationValue(aw->aw_aiter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue