summaryrefslogtreecommitdiff
path: root/Objects/genobject.c
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2015-05-22 11:13:20 +0300
committerSerhiy Storchaka <storchaka@gmail.com>2015-05-22 11:13:20 +0300
commit647cf1e9cabefeae8524838ab0bf2f9cc3ce16cc (patch)
treece284ff2c495723708e6b67dbfa5d5ad57d5fe5b /Objects/genobject.c
parent7bc6483a733e3f7884318221df9886928e97203a (diff)
parent2f27cf5854a27f26774e9721383f69ac968b3c84 (diff)
downloadcpython-647cf1e9cabefeae8524838ab0bf2f9cc3ce16cc.tar.gz
Issue #24257: Fixed incorrect uses of PyObject_IsInstance().
Fixed segmentation fault in sqlite3.Row constructor with faked cursor type. Fixed system error in the comparison of faked types.SimpleNamespace.
Diffstat (limited to 'Objects/genobject.c')
-rw-r--r--Objects/genobject.c219
1 files changed, 196 insertions, 23 deletions
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 67e6ef9e00..555e4fd76e 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -12,6 +12,8 @@ gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
{
Py_VISIT((PyObject *)gen->gi_frame);
Py_VISIT(gen->gi_code);
+ Py_VISIT(gen->gi_name);
+ Py_VISIT(gen->gi_qualname);
return 0;
}
@@ -22,6 +24,19 @@ _PyGen_Finalize(PyObject *self)
PyObject *res;
PyObject *error_type, *error_value, *error_traceback;
+ /* If `gen` is a coroutine, and if it was never awaited on,
+ issue a RuntimeWarning. */
+ if (gen->gi_code != NULL
+ && ((PyCodeObject *)gen->gi_code)->co_flags & (CO_COROUTINE
+ | CO_ITERABLE_COROUTINE)
+ && gen->gi_frame != NULL
+ && gen->gi_frame->f_lasti == -1
+ && !PyErr_Occurred()
+ && PyErr_WarnFormat(PyExc_RuntimeWarning, 1,
+ "coroutine '%.50S' was never awaited",
+ gen->gi_qualname))
+ return;
+
if (gen->gi_frame == NULL || gen->gi_frame->f_stacktop == NULL)
/* Generator isn't paused, so no need to close */
return;
@@ -58,6 +73,8 @@ gen_dealloc(PyGenObject *gen)
_PyObject_GC_UNTRACK(self);
Py_CLEAR(gen->gi_frame);
Py_CLEAR(gen->gi_code);
+ Py_CLEAR(gen->gi_name);
+ Py_CLEAR(gen->gi_qualname);
PyObject_GC_Del(gen);
}
@@ -126,6 +143,31 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc)
}
Py_CLEAR(result);
}
+ else if (!result) {
+ /* Check for __future__ generator_stop and conditionally turn
+ * a leaking StopIteration into RuntimeError (with its cause
+ * set appropriately). */
+ if ((((PyCodeObject *)gen->gi_code)->co_flags &
+ (CO_FUTURE_GENERATOR_STOP | CO_COROUTINE | CO_ITERABLE_COROUTINE))
+ && PyErr_ExceptionMatches(PyExc_StopIteration))
+ {
+ PyObject *exc, *val, *val2, *tb;
+ PyErr_Fetch(&exc, &val, &tb);
+ PyErr_NormalizeException(&exc, &val, &tb);
+ if (tb != NULL)
+ PyException_SetTraceback(val, tb);
+ Py_DECREF(exc);
+ Py_XDECREF(tb);
+ PyErr_SetString(PyExc_RuntimeError,
+ "generator raised StopIteration");
+ PyErr_Fetch(&exc, &val2, &tb);
+ PyErr_NormalizeException(&exc, &val2, &tb);
+ Py_INCREF(val);
+ PyException_SetCause(val2, val);
+ PyException_SetContext(val2, val);
+ PyErr_Restore(exc, val2, tb);
+ }
+ }
if (!result || f->f_stacktop == NULL) {
/* generator can't be rerun, so release the frame */
@@ -373,11 +415,13 @@ failed_throw:
static PyObject *
gen_iternext(PyGenObject *gen)
{
- PyObject *val = NULL;
- PyObject *ret;
- ret = gen_send_ex(gen, val, 0);
- Py_XDECREF(val);
- return ret;
+ if (((PyCodeObject*)gen->gi_code)->co_flags & CO_COROUTINE) {
+ PyErr_SetString(PyExc_TypeError,
+ "coroutine-objects do not support iteration");
+ return NULL;
+ }
+
+ return gen_send_ex(gen, NULL, 0);
}
/*
@@ -433,34 +477,93 @@ _PyGen_FetchStopIterationValue(PyObject **pvalue) {
static PyObject *
gen_repr(PyGenObject *gen)
{
- return PyUnicode_FromFormat("<generator object %S at %p>",
- ((PyCodeObject *)gen->gi_code)->co_name,
- gen);
+ if (PyGen_CheckCoroutineExact(gen)) {
+ return PyUnicode_FromFormat("<coroutine object %S at %p>",
+ gen->gi_qualname, gen);
+ }
+ else {
+ return PyUnicode_FromFormat("<generator object %S at %p>",
+ gen->gi_qualname, gen);
+ }
}
+static PyObject *
+gen_get_name(PyGenObject *op)
+{
+ Py_INCREF(op->gi_name);
+ return op->gi_name;
+}
+
+static int
+gen_set_name(PyGenObject *op, PyObject *value)
+{
+ PyObject *tmp;
+
+ /* Not legal to del gen.gi_name or to set it to anything
+ * other than a string object. */
+ if (value == NULL || !PyUnicode_Check(value)) {
+ PyErr_SetString(PyExc_TypeError,
+ "__name__ must be set to a string object");
+ return -1;
+ }
+ tmp = op->gi_name;
+ Py_INCREF(value);
+ op->gi_name = value;
+ Py_DECREF(tmp);
+ return 0;
+}
static PyObject *
-gen_get_name(PyGenObject *gen)
+gen_get_qualname(PyGenObject *op)
{
- PyObject *name = ((PyCodeObject *)gen->gi_code)->co_name;
- Py_INCREF(name);
- return name;
+ Py_INCREF(op->gi_qualname);
+ return op->gi_qualname;
}
+static PyObject *
+gen_get_iter(PyGenObject *gen)
+{
+ if (((PyCodeObject*)gen->gi_code)->co_flags & CO_COROUTINE) {
+ PyErr_SetString(PyExc_TypeError,
+ "coroutine-objects do not support iteration");
+ return NULL;
+ }
+
+ Py_INCREF(gen);
+ return (PyObject *)gen;
+}
-PyDoc_STRVAR(gen__name__doc__,
-"Return the name of the generator's associated code object.");
+static int
+gen_set_qualname(PyGenObject *op, PyObject *value)
+{
+ PyObject *tmp;
+
+ /* Not legal to del gen.__qualname__ or to set it to anything
+ * other than a string object. */
+ if (value == NULL || !PyUnicode_Check(value)) {
+ PyErr_SetString(PyExc_TypeError,
+ "__qualname__ must be set to a string object");
+ return -1;
+ }
+ tmp = op->gi_qualname;
+ Py_INCREF(value);
+ op->gi_qualname = value;
+ Py_DECREF(tmp);
+ return 0;
+}
static PyGetSetDef gen_getsetlist[] = {
- {"__name__", (getter)gen_get_name, NULL, gen__name__doc__},
- {NULL}
+ {"__name__", (getter)gen_get_name, (setter)gen_set_name,
+ PyDoc_STR("name of the generator")},
+ {"__qualname__", (getter)gen_get_qualname, (setter)gen_set_qualname,
+ PyDoc_STR("qualified name of the generator")},
+ {NULL} /* Sentinel */
};
-
static PyMemberDef gen_memberlist[] = {
- {"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), READONLY},
- {"gi_running", T_BOOL, offsetof(PyGenObject, gi_running), READONLY},
- {"gi_code", T_OBJECT, offsetof(PyGenObject, gi_code), READONLY},
+ {"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), READONLY},
+ {"gi_running", T_BOOL, offsetof(PyGenObject, gi_running), READONLY},
+ {"gi_code", T_OBJECT, offsetof(PyGenObject, gi_code), READONLY},
{NULL} /* Sentinel */
};
@@ -481,7 +584,7 @@ PyTypeObject PyGen_Type = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
- 0, /* tp_reserved */
+ 0, /* tp_as_async */
(reprfunc)gen_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
@@ -499,7 +602,7 @@ PyTypeObject PyGen_Type = {
0, /* tp_clear */
0, /* tp_richcompare */
offsetof(PyGenObject, gi_weakreflist), /* tp_weaklistoffset */
- PyObject_SelfIter, /* tp_iter */
+ (getiterfunc)gen_get_iter, /* tp_iter */
(iternextfunc)gen_iternext, /* tp_iternext */
gen_methods, /* tp_methods */
gen_memberlist, /* tp_members */
@@ -526,7 +629,7 @@ PyTypeObject PyGen_Type = {
};
PyObject *
-PyGen_New(PyFrameObject *f)
+PyGen_NewWithQualName(PyFrameObject *f, PyObject *name, PyObject *qualname)
{
PyGenObject *gen = PyObject_GC_New(PyGenObject, &PyGen_Type);
if (gen == NULL) {
@@ -539,10 +642,26 @@ PyGen_New(PyFrameObject *f)
gen->gi_code = (PyObject *)(f->f_code);
gen->gi_running = 0;
gen->gi_weakreflist = NULL;
+ if (name != NULL)
+ gen->gi_name = name;
+ else
+ gen->gi_name = ((PyCodeObject *)gen->gi_code)->co_name;
+ Py_INCREF(gen->gi_name);
+ if (qualname != NULL)
+ gen->gi_qualname = qualname;
+ else
+ gen->gi_qualname = gen->gi_name;
+ Py_INCREF(gen->gi_qualname);
_PyObject_GC_TRACK(gen);
return (PyObject *)gen;
}
+PyObject *
+PyGen_New(PyFrameObject *f)
+{
+ return PyGen_NewWithQualName(f, NULL, NULL);
+}
+
int
PyGen_NeedsFinalizing(PyGenObject *gen)
{
@@ -560,3 +679,57 @@ PyGen_NeedsFinalizing(PyGenObject *gen)
/* No blocks except loops, it's safe to skip finalization. */
return 0;
}
+
+/*
+ * This helper function returns an awaitable for `o`:
+ * - `o` if `o` is a coroutine-object;
+ * - `type(o)->tp_as_async->am_await(o)`
+ *
+ * Raises a TypeError if it's not possible to return
+ * an awaitable and returns NULL.
+ */
+PyObject *
+_PyGen_GetAwaitableIter(PyObject *o)
+{
+ getawaitablefunc getter = NULL;
+ PyTypeObject *ot;
+
+ if (PyGen_CheckCoroutineExact(o)) {
+ /* Fast path. It's a central function for 'await'. */
+ Py_INCREF(o);
+ return o;
+ }
+
+ ot = Py_TYPE(o);
+ if (ot->tp_as_async != NULL) {
+ getter = ot->tp_as_async->am_await;
+ }
+ if (getter != NULL) {
+ PyObject *res = (*getter)(o);
+ if (res != NULL) {
+ if (!PyIter_Check(res)) {
+ PyErr_Format(PyExc_TypeError,
+ "__await__() returned non-iterator "
+ "of type '%.100s'",
+ Py_TYPE(res)->tp_name);
+ Py_CLEAR(res);
+ }
+ else {
+ if (PyGen_CheckCoroutineExact(res)) {
+ /* __await__ must return an *iterator*, not
+ a coroutine or another awaitable (see PEP 492) */
+ PyErr_SetString(PyExc_TypeError,
+ "__await__() returned a coroutine");
+ Py_CLEAR(res);
+ }
+ }
+ }
+ return res;
+ }
+
+ PyErr_Format(PyExc_TypeError,
+ "object %.100s can't be used in 'await' expression",
+ ot->tp_name);
+
+ return NULL;
+}