bpo-45711: use exc_value instead of exc_type to determine if exc_info… · python/cpython@c456dfa
@@ -79,11 +79,16 @@ _PyErr_StackItem *
7979_PyErr_GetTopmostException(PyThreadState *tstate)
8080{
8181_PyErr_StackItem *exc_info = tstate->exc_info;
82-while ((exc_info->exc_type == NULL || exc_info->exc_type == Py_None) &&
82+assert(exc_info);
83+84+while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) &&
8385exc_info->previous_item != NULL)
8486 {
87+assert(exc_info->exc_type == NULL || exc_info->exc_type == Py_None);
8588exc_info = exc_info->previous_item;
8689 }
90+assert(exc_info->previous_item == NULL ||
91+ (exc_info->exc_type != NULL && exc_info->exc_type != Py_None));
8792return exc_info;
8893}
8994@@ -471,10 +476,20 @@ _PyErr_GetExcInfo(PyThreadState *tstate,
471476PyObject **p_type, PyObject **p_value, PyObject **p_traceback)
472477{
473478_PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate);
474- *p_type = exc_info->exc_type;
479+475480*p_value = exc_info->exc_value;
476481*p_traceback = exc_info->exc_traceback;
477482483+if (*p_value == NULL || *p_value == Py_None) {
484+assert(exc_info->exc_type == NULL || exc_info->exc_type == Py_None);
485+*p_type = Py_None;
486+ }
487+else {
488+assert(PyExceptionInstance_Check(*p_value));
489+assert(exc_info->exc_type == PyExceptionInstance_Class(*p_value));
490+*p_type = PyExceptionInstance_Class(*p_value);
491+ }
492+478493Py_XINCREF(*p_type);
479494Py_XINCREF(*p_value);
480495Py_XINCREF(*p_traceback);
@@ -507,42 +522,66 @@ PyErr_SetExcInfo(PyObject *p_type, PyObject *p_value, PyObject *p_traceback)
507522Py_XDECREF(oldtraceback);
508523}
509524525+526+PyObject*
527+_PyErr_StackItemToExcInfoTuple(_PyErr_StackItem *err_info)
528+{
529+PyObject *exc_value = err_info->exc_value;
530+if (exc_value == NULL) {
531+exc_value = Py_None;
532+ }
533+534+assert(exc_value == Py_None || PyExceptionInstance_Check(exc_value));
535+536+PyObject *exc_type = PyExceptionInstance_Check(exc_value) ?
537+PyExceptionInstance_Class(exc_value) :
538+Py_None;
539+540+return Py_BuildValue(
541+"(OOO)",
542+exc_type,
543+exc_value,
544+err_info->exc_traceback != NULL ?
545+err_info->exc_traceback : Py_None);
546+}
547+548+510549/* Like PyErr_Restore(), but if an exception is already set,
511550 set the context associated with it.
512551513552 The caller is responsible for ensuring that this call won't create
514553 any cycles in the exception context chain. */
515554void
516-_PyErr_ChainExceptions(PyObject *exc, PyObject *val, PyObject *tb)
555+_PyErr_ChainExceptions(PyObject *typ, PyObject *val, PyObject *tb)
517556{
518-if (exc == NULL)
557+if (typ == NULL)
519558return;
520559521560PyThreadState *tstate = _PyThreadState_GET();
522561523-if (!PyExceptionClass_Check(exc)) {
562+if (!PyExceptionClass_Check(typ)) {
524563_PyErr_Format(tstate, PyExc_SystemError,
525564"_PyErr_ChainExceptions: "
526565"exception %R is not a BaseException subclass",
527-exc);
566+typ);
528567return;
529568 }
530569531570if (_PyErr_Occurred(tstate)) {
532-PyObject *exc2, *val2, *tb2;
533-_PyErr_Fetch(tstate, &exc2, &val2, &tb2);
534-_PyErr_NormalizeException(tstate, &exc, &val, &tb);
571+PyObject *typ2, *val2, *tb2;
572+_PyErr_Fetch(tstate, &typ2, &val2, &tb2);
573+_PyErr_NormalizeException(tstate, &typ, &val, &tb);
535574if (tb != NULL) {
536575PyException_SetTraceback(val, tb);
537576Py_DECREF(tb);
538577 }
539-Py_DECREF(exc);
540-_PyErr_NormalizeException(tstate, &exc2, &val2, &tb2);
578+Py_DECREF(typ);
579+_PyErr_NormalizeException(tstate, &typ2, &val2, &tb2);
541580PyException_SetContext(val2, val);
542-_PyErr_Restore(tstate, exc2, val2, tb2);
581+_PyErr_Restore(tstate, typ2, val2, tb2);
543582 }
544583else {
545-_PyErr_Restore(tstate, exc, val, tb);
584+_PyErr_Restore(tstate, typ, val, tb);
546585 }
547586}
548587@@ -567,7 +606,11 @@ _PyErr_ChainStackItem(_PyErr_StackItem *exc_info)
567606 } else {
568607exc_info_given = 1;
569608 }
570-if (exc_info->exc_type == NULL || exc_info->exc_type == Py_None) {
609+610+assert( (exc_info->exc_type == NULL || exc_info->exc_type == Py_None) ==
611+ (exc_info->exc_value == NULL || exc_info->exc_value == Py_None) );
612+613+if (exc_info->exc_value == NULL || exc_info->exc_value == Py_None) {
571614return;
572615 }
573616@@ -579,21 +622,32 @@ _PyErr_ChainStackItem(_PyErr_StackItem *exc_info)
579622tstate->exc_info = exc_info;
580623 }
581624582-PyObject *exc, *val, *tb;
583-_PyErr_Fetch(tstate, &exc, &val, &tb);
625+PyObject *typ, *val, *tb;
626+_PyErr_Fetch(tstate, &typ, &val, &tb);
584627585-PyObject *exc2, *val2, *tb2;
586-exc2 = exc_info->exc_type;
628+PyObject *typ2, *val2, *tb2;
629+typ2 = exc_info->exc_type;
587630val2 = exc_info->exc_value;
588631tb2 = exc_info->exc_traceback;
589-_PyErr_NormalizeException(tstate, &exc2, &val2, &tb2);
632+#ifdef Py_DEBUG
633+PyObject *typ2_before = typ2;
634+PyObject *val2_before = val2;
635+PyObject *tb2_before = tb2;
636+#endif
637+_PyErr_NormalizeException(tstate, &typ2, &val2, &tb2);
638+#ifdef Py_DEBUG
639+/* exc_info should already be normalized */
640+assert(typ2 == typ2_before);
641+assert(val2 == val2_before);
642+assert(tb2 == tb2_before);
643+#endif
590644if (tb2 != NULL) {
591645PyException_SetTraceback(val2, tb2);
592646 }
593647594648/* _PyErr_SetObject sets the context from PyThreadState. */
595-_PyErr_SetObject(tstate, exc, val);
596-Py_DECREF(exc); // since _PyErr_Occurred was true
649+_PyErr_SetObject(tstate, typ, val);
650+Py_DECREF(typ); // since _PyErr_Occurred was true
597651Py_XDECREF(val);
598652Py_XDECREF(tb);
599653