diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2016-11-06 16:44:42 (GMT) |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2016-11-06 16:44:42 (GMT) |
commit | 24411f8a8daace4ebf8abd41091b681160b4fb89 (patch) | |
tree | f82a4ca89149075c9e764e82093c253b8e03de46 /Objects/genobject.c | |
parent | 04b3d8b6973150bf0c3ce9ec0ffe5cabf4161b7b (diff) | |
download | cpython-24411f8a8daace4ebf8abd41091b681160b4fb89.zip cpython-24411f8a8daace4ebf8abd41091b681160b4fb89.tar.gz cpython-24411f8a8daace4ebf8abd41091b681160b4fb89.tar.bz2 |
Issue #23996: Added _PyGen_SetStopIterationValue for safe raising
StopIteration with value. More safely handle non-normalized exceptions
in -_PyGen_FetchStopIterationValue.
Diffstat (limited to 'Objects/genobject.c')
-rw-r--r-- | Objects/genobject.c | 60 |
1 files changed, 50 insertions, 10 deletions
diff --git a/Objects/genobject.c b/Objects/genobject.c index 9172e6a..0d5d54f 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -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); } @@ -460,6 +455,43 @@ gen_iternext(PyGenObject *gen) } /* + * 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; } |