diff options
author | Mark Shannon <mark@hotpy.org> | 2017-10-22 21:41:51 (GMT) |
---|---|---|
committer | Antoine Pitrou <pitrou@free.fr> | 2017-10-22 21:41:51 (GMT) |
commit | ae3087c6382011c47db82fea4d05f8bbf514265d (patch) | |
tree | c5d832a760d9898700f1ca397a5a305734b3d77a /Objects/genobject.c | |
parent | 91dc64ba3f51100540b2ab6c6cd72c3bb18a6d49 (diff) | |
download | cpython-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/genobject.c')
-rw-r--r-- | Objects/genobject.c | 46 |
1 files changed, 35 insertions, 11 deletions
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 |