summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2017-10-22 21:41:51 (GMT)
committerAntoine Pitrou <pitrou@free.fr>2017-10-22 21:41:51 (GMT)
commitae3087c6382011c47db82fea4d05f8bbf514265d (patch)
treec5d832a760d9898700f1ca397a5a305734b3d77a /Objects
parent91dc64ba3f51100540b2ab6c6cd72c3bb18a6d49 (diff)
downloadcpython-ae3087c6382011c47db82fea4d05f8bbf514265d.zip
cpython-ae3087c6382011c47db82fea4d05f8bbf514265d.tar.gz
cpython-ae3087c6382011c47db82fea4d05f8bbf514265d.tar.bz2
Move exc state to generator. Fixes bpo-25612 (#1773)
Move exception state information from frame objects to coroutine (generator/thread) object where it belongs.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/frameobject.c13
-rw-r--r--Objects/genobject.c46
2 files changed, 36 insertions, 23 deletions
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 8739596..6ab3a22 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -379,8 +379,7 @@ static PyGetSetDef frame_getsetlist[] = {
* ob_type, ob_size, f_code, f_valuestack;
- * f_locals, f_trace,
- f_exc_type, f_exc_value, f_exc_traceback are NULL;
+ * f_locals, f_trace are NULL;
* f_localsplus does not require re-allocation and
the local variables in f_localsplus are NULL.
@@ -438,9 +437,6 @@ frame_dealloc(PyFrameObject *f)
Py_DECREF(f->f_globals);
Py_CLEAR(f->f_locals);
Py_CLEAR(f->f_trace);
- Py_CLEAR(f->f_exc_type);
- Py_CLEAR(f->f_exc_value);
- Py_CLEAR(f->f_exc_traceback);
co = f->f_code;
if (co->co_zombieframe == NULL)
@@ -469,9 +465,6 @@ frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
Py_VISIT(f->f_globals);
Py_VISIT(f->f_locals);
Py_VISIT(f->f_trace);
- Py_VISIT(f->f_exc_type);
- Py_VISIT(f->f_exc_value);
- Py_VISIT(f->f_exc_traceback);
/* locals */
slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars);
@@ -502,9 +495,6 @@ frame_tp_clear(PyFrameObject *f)
f->f_stacktop = NULL;
f->f_executing = 0;
- Py_CLEAR(f->f_exc_type);
- Py_CLEAR(f->f_exc_value);
- Py_CLEAR(f->f_exc_traceback);
Py_CLEAR(f->f_trace);
/* locals */
@@ -698,7 +688,6 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
f->f_localsplus[i] = NULL;
f->f_locals = NULL;
f->f_trace = NULL;
- f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL;
}
f->f_stacktop = f->f_valuestack;
f->f_builtins = builtins;
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 5d5798c..7793a54 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -16,6 +16,15 @@ static char *NON_INIT_CORO_MSG = "can't send non-None value to a "
static char *ASYNC_GEN_IGNORED_EXIT_MSG =
"async generator ignored GeneratorExit";
+static inline int
+exc_state_traverse(_PyErr_StackItem *exc_state, visitproc visit, void *arg)
+{
+ Py_VISIT(exc_state->exc_type);
+ Py_VISIT(exc_state->exc_value);
+ Py_VISIT(exc_state->exc_traceback);
+ return 0;
+}
+
static int
gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
{
@@ -23,7 +32,7 @@ gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
Py_VISIT(gen->gi_code);
Py_VISIT(gen->gi_name);
Py_VISIT(gen->gi_qualname);
- return 0;
+ return exc_state_traverse(&gen->gi_exc_state, visit, arg);
}
void
@@ -87,6 +96,21 @@ _PyGen_Finalize(PyObject *self)
PyErr_Restore(error_type, error_value, error_traceback);
}
+static inline void
+exc_state_clear(_PyErr_StackItem *exc_state)
+{
+ PyObject *t, *v, *tb;
+ t = exc_state->exc_type;
+ v = exc_state->exc_value;
+ tb = exc_state->exc_traceback;
+ exc_state->exc_type = NULL;
+ exc_state->exc_value = NULL;
+ exc_state->exc_traceback = NULL;
+ Py_XDECREF(t);
+ Py_XDECREF(v);
+ Py_XDECREF(tb);
+}
+
static void
gen_dealloc(PyGenObject *gen)
{
@@ -116,6 +140,7 @@ gen_dealloc(PyGenObject *gen)
Py_CLEAR(gen->gi_code);
Py_CLEAR(gen->gi_name);
Py_CLEAR(gen->gi_qualname);
+ exc_state_clear(&gen->gi_exc_state);
PyObject_GC_Del(gen);
}
@@ -187,7 +212,11 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
f->f_back = tstate->frame;
gen->gi_running = 1;
+ gen->gi_exc_state.previous_item = tstate->exc_info;
+ tstate->exc_info = &gen->gi_exc_state;
result = PyEval_EvalFrameEx(f, exc);
+ tstate->exc_info = gen->gi_exc_state.previous_item;
+ gen->gi_exc_state.previous_item = NULL;
gen->gi_running = 0;
/* Don't keep the reference to f_back any longer than necessary. It
@@ -281,16 +310,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
if (!result || f->f_stacktop == NULL) {
/* generator can't be rerun, so release the frame */
/* first clean reference cycle through stored exception traceback */
- PyObject *t, *v, *tb;
- t = f->f_exc_type;
- v = f->f_exc_value;
- tb = f->f_exc_traceback;
- f->f_exc_type = NULL;
- f->f_exc_value = NULL;
- f->f_exc_traceback = NULL;
- Py_XDECREF(t);
- Py_XDECREF(v);
- Py_XDECREF(tb);
+ exc_state_clear(&gen->gi_exc_state);
gen->gi_frame->f_gen = NULL;
gen->gi_frame = NULL;
Py_DECREF(f);
@@ -810,6 +830,10 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
gen->gi_code = (PyObject *)(f->f_code);
gen->gi_running = 0;
gen->gi_weakreflist = NULL;
+ gen->gi_exc_state.exc_type = NULL;
+ gen->gi_exc_state.exc_value = NULL;
+ gen->gi_exc_state.exc_traceback = NULL;
+ gen->gi_exc_state.previous_item = NULL;
if (name != NULL)
gen->gi_name = name;
else