summaryrefslogtreecommitdiff
path: root/Objects/genobject.c
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2016-11-06 18:47:03 +0200
committerSerhiy Storchaka <storchaka@gmail.com>2016-11-06 18:47:03 +0200
commit2b3808dba0cbce798df9a0f2c299328f94f324fa (patch)
tree46a24db26a0e6f83ff56082afa976fbd8292eae4 /Objects/genobject.c
parentf4f0184fa29983a139c552a3c493ba9c94cc9ae1 (diff)
parente6a2d8dd51d48c89c458ed35dac2c64409e3cf92 (diff)
downloadcpython-2b3808dba0cbce798df9a0f2c299328f94f324fa.tar.gz
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.c72
1 files changed, 51 insertions, 21 deletions
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 7bcf016c34..70d6e1492a 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -208,16 +208,9 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
}
}
else {
- PyObject *e = PyObject_CallFunctionObjArgs(
- PyExc_StopIteration, result, NULL);
-
/* Async generators cannot return anything but None */
assert(!PyAsyncGen_CheckExact(gen));
-
- if (e != NULL) {
- PyErr_SetObject(PyExc_StopIteration, e);
- Py_DECREF(e);
- }
+ _PyGen_SetStopIterationValue(result);
}
Py_CLEAR(result);
}
@@ -562,6 +555,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.
*
@@ -571,7 +601,8 @@ gen_iternext(PyGenObject *gen)
*/
int
-_PyGen_FetchStopIterationValue(PyObject **pvalue) {
+_PyGen_FetchStopIterationValue(PyObject **pvalue)
+{
PyObject *et, *ev, *tb;
PyObject *value = NULL;
@@ -583,8 +614,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 */
@@ -1106,7 +1144,7 @@ typedef struct {
static PyObject *
aiter_wrapper_iternext(PyAIterWrapper *aw)
{
- PyErr_SetObject(PyExc_StopIteration, aw->ags_aiter);
+ _PyGen_SetStopIterationValue(aw->ags_aiter);
return NULL;
}
@@ -1504,16 +1542,8 @@ async_gen_unwrap_value(PyAsyncGenObject *gen, PyObject *result)
if (_PyAsyncGenWrappedValue_CheckExact(result)) {
/* async yield */
- PyObject *e = PyObject_CallFunctionObjArgs(
- PyExc_StopIteration,
- ((_PyAsyncGenWrappedValue*)result)->agw_val,
- NULL);
+ _PyGen_SetStopIterationValue(((_PyAsyncGenWrappedValue*)result)->agw_val);
Py_DECREF(result);
- if (e == NULL) {
- return NULL;
- }
- PyErr_SetObject(PyExc_StopIteration, e);
- Py_DECREF(e);
return NULL;
}