From 847fcdb369177e20d1ad04c288113d4fe2a83f55 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 2 Dec 2021 12:34:26 +0000 Subject: [PATCH 1/5] bpo-45711: Remove unnecessary normalization of exc_info --- Python/errors.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/Python/errors.c b/Python/errors.c index 0a8b5a257fb2c7..44d2773acdb5cd 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -647,26 +647,6 @@ _PyErr_ChainStackItem(_PyErr_StackItem *exc_info) PyObject *typ, *val, *tb; _PyErr_Fetch(tstate, &typ, &val, &tb); - PyObject *typ2, *val2, *tb2; - typ2 = exc_info->exc_type; - val2 = exc_info->exc_value; - tb2 = exc_info->exc_traceback; -#ifdef Py_DEBUG - PyObject *typ2_before = typ2; - PyObject *val2_before = val2; - PyObject *tb2_before = tb2; -#endif - _PyErr_NormalizeException(tstate, &typ2, &val2, &tb2); -#ifdef Py_DEBUG - /* exc_info should already be normalized */ - assert(typ2 == typ2_before); - assert(val2 == val2_before); - assert(tb2 == tb2_before); -#endif - if (tb2 != NULL) { - PyException_SetTraceback(val2, tb2); - } - /* _PyErr_SetObject sets the context from PyThreadState. */ _PyErr_SetObject(tstate, typ, val); Py_DECREF(typ); // since _PyErr_Occurred was true From acc65e65d74d64cddaee5351695e18569ec78ba3 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 2 Dec 2021 16:11:42 +0000 Subject: [PATCH 2/5] put the traceback update back in _PyErr_ChainStackItem --- Python/errors.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Python/errors.c b/Python/errors.c index 44d2773acdb5cd..8db4d0823d31ec 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -636,6 +636,10 @@ _PyErr_ChainStackItem(_PyErr_StackItem *exc_info) return; } + if (exc_info->exc_traceback) { + PyException_SetTraceback(exc_info->exc_value, exc_info->exc_traceback); + } + _PyErr_StackItem *saved_exc_info; if (exc_info_given) { /* Temporarily set the thread state's exc_info since this is what From a995431ef96798cdabc7f9b5f69e29abe86eb65a Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 2 Dec 2021 16:57:41 +0000 Subject: [PATCH 3/5] normalize exceptions after Fetch when they are about to be stored as a StackItem (exc_info) --- Modules/_asynciomodule.c | 19 ++++++++++++------- Python/errors.c | 4 ---- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index df6644ba248ed7..267faacde8a171 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -2702,6 +2702,11 @@ task_step_impl(TaskObj *task, PyObject *exc) if (PyErr_ExceptionMatches(asyncio_CancelledError)) { /* CancelledError */ PyErr_Fetch(&et, &ev, &tb); + assert(et); + PyErr_NormalizeException(&et, &ev, &tb); + if (tb != NULL) { + PyException_SetTraceback(ev, tb); + } FutureObj *fut = (FutureObj*)task; _PyErr_StackItem *exc_state = &fut->fut_cancelled_exc_state; @@ -2714,14 +2719,12 @@ task_step_impl(TaskObj *task, PyObject *exc) /* Some other exception; pop it and call Task.set_exception() */ PyErr_Fetch(&et, &ev, &tb); - assert(et); - if (!ev || !PyObject_TypeCheck(ev, (PyTypeObject *) et)) { - PyErr_NormalizeException(&et, &ev, &tb); - } + PyErr_NormalizeException(&et, &ev, &tb); if (tb != NULL) { PyException_SetTraceback(ev, tb); } + o = future_set_exception((FutureObj*)task, ev); if (!o) { /* An exception in Task.set_exception() */ @@ -2965,7 +2968,7 @@ task_step(TaskObj *task, PyObject *exc) PyObject *et, *ev, *tb; PyErr_Fetch(&et, &ev, &tb); leave_task(task->task_loop, (PyObject*)task); - _PyErr_ChainExceptions(et, ev, tb); + _PyErr_ChainExceptions(et, ev, tb); /* Normalizes (et, ev, tb) */ return NULL; } else { @@ -3014,8 +3017,10 @@ task_wakeup(TaskObj *task, PyObject *o) } PyErr_Fetch(&et, &ev, &tb); - if (!ev || !PyObject_TypeCheck(ev, (PyTypeObject *) et)) { - PyErr_NormalizeException(&et, &ev, &tb); + assert(et); + PyErr_NormalizeException(&et, &ev, &tb); + if (tb != NULL) { + PyException_SetTraceback(ev, tb); } result = task_step(task, ev); diff --git a/Python/errors.c b/Python/errors.c index 8db4d0823d31ec..44d2773acdb5cd 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -636,10 +636,6 @@ _PyErr_ChainStackItem(_PyErr_StackItem *exc_info) return; } - if (exc_info->exc_traceback) { - PyException_SetTraceback(exc_info->exc_value, exc_info->exc_traceback); - } - _PyErr_StackItem *saved_exc_info; if (exc_info_given) { /* Temporarily set the thread state's exc_info since this is what From 6ce38484e0f3e6af74032e626a27eb7e269e85cf Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 2 Dec 2021 17:22:07 +0000 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NEWS.d/next/Library/2021-12-02-17-22-06.bpo-45711.D6jsdv.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2021-12-02-17-22-06.bpo-45711.D6jsdv.rst diff --git a/Misc/NEWS.d/next/Library/2021-12-02-17-22-06.bpo-45711.D6jsdv.rst b/Misc/NEWS.d/next/Library/2021-12-02-17-22-06.bpo-45711.D6jsdv.rst new file mode 100644 index 00000000000000..b2b57730c3ba80 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-12-02-17-22-06.bpo-45711.D6jsdv.rst @@ -0,0 +1 @@ +Make :mod:`asyncio` normalize exceptions as soon as they are captured with :c:func:`PyErr_Fetch`, and before they are stored as an exc_info triplet. This brings :mod:`asyncio` in line with the rest of the codebase, where an exc_info triplet is always normalized. \ No newline at end of file From e1a719a424958f7bdee1b3c851b2f10166f5af6e Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 2 Dec 2021 22:12:06 +0000 Subject: [PATCH 5/5] Revert "bpo-45711: Remove unnecessary normalization of exc_info" This reverts commit 847fcdb369177e20d1ad04c288113d4fe2a83f55. --- Python/errors.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Python/errors.c b/Python/errors.c index 44d2773acdb5cd..0a8b5a257fb2c7 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -647,6 +647,26 @@ _PyErr_ChainStackItem(_PyErr_StackItem *exc_info) PyObject *typ, *val, *tb; _PyErr_Fetch(tstate, &typ, &val, &tb); + PyObject *typ2, *val2, *tb2; + typ2 = exc_info->exc_type; + val2 = exc_info->exc_value; + tb2 = exc_info->exc_traceback; +#ifdef Py_DEBUG + PyObject *typ2_before = typ2; + PyObject *val2_before = val2; + PyObject *tb2_before = tb2; +#endif + _PyErr_NormalizeException(tstate, &typ2, &val2, &tb2); +#ifdef Py_DEBUG + /* exc_info should already be normalized */ + assert(typ2 == typ2_before); + assert(val2 == val2_before); + assert(tb2 == tb2_before); +#endif + if (tb2 != NULL) { + PyException_SetTraceback(val2, tb2); + } + /* _PyErr_SetObject sets the context from PyThreadState. */ _PyErr_SetObject(tstate, typ, val); Py_DECREF(typ); // since _PyErr_Occurred was true