bpo-45711: Change exc_info related APIs to derive type and traceback … · python/cpython@8a45ca5
@@ -470,25 +470,43 @@ PyErr_Clear(void)
470470_PyErr_Clear(tstate);
471471}
472472473+static PyObject*
474+get_exc_type(PyObject *exc_value) /* returns a borrowed ref */
475+{
476+if (exc_value == NULL || exc_value == Py_None) {
477+return Py_None;
478+ }
479+else {
480+assert(PyExceptionInstance_Check(exc_value));
481+PyObject *type = PyExceptionInstance_Class(exc_value);
482+assert(type != NULL);
483+return type;
484+ }
485+}
486+487+static PyObject*
488+get_exc_traceback(PyObject *exc_value) /* returns a borrowed ref */
489+{
490+if (exc_value == NULL || exc_value == Py_None) {
491+return Py_None;
492+ }
493+else {
494+assert(PyExceptionInstance_Check(exc_value));
495+PyObject *tb = PyException_GetTraceback(exc_value);
496+Py_XDECREF(tb);
497+return tb ? tb : Py_None;
498+ }
499+}
473500474501void
475502_PyErr_GetExcInfo(PyThreadState *tstate,
476503PyObject **p_type, PyObject **p_value, PyObject **p_traceback)
477504{
478505_PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate);
479506507+*p_type = get_exc_type(exc_info->exc_value);
480508*p_value = exc_info->exc_value;
481-*p_traceback = exc_info->exc_traceback;
482-483-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- }
509+*p_traceback = get_exc_traceback(exc_info->exc_value);
492510493511Py_XINCREF(*p_type);
494512Py_XINCREF(*p_value);
@@ -504,7 +522,7 @@ PyErr_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback)
504522}
505523506524void
507-PyErr_SetExcInfo(PyObject *p_type, PyObject *p_value, PyObject *p_traceback)
525+PyErr_SetExcInfo(PyObject *type, PyObject *value, PyObject *traceback)
508526{
509527PyObject *oldtype, *oldvalue, *oldtraceback;
510528PyThreadState *tstate = _PyThreadState_GET();
@@ -513,9 +531,16 @@ PyErr_SetExcInfo(PyObject *p_type, PyObject *p_value, PyObject *p_traceback)
513531oldvalue = tstate->exc_info->exc_value;
514532oldtraceback = tstate->exc_info->exc_traceback;
515533516-tstate->exc_info->exc_type = p_type;
517-tstate->exc_info->exc_value = p_value;
518-tstate->exc_info->exc_traceback = p_traceback;
534+535+tstate->exc_info->exc_type = get_exc_type(value);
536+Py_XINCREF(tstate->exc_info->exc_type);
537+tstate->exc_info->exc_value = value;
538+tstate->exc_info->exc_traceback = get_exc_traceback(value);
539+Py_XINCREF(tstate->exc_info->exc_traceback);
540+541+/* These args are no longer used, but we still need to steal a ref */
542+Py_XDECREF(type);
543+Py_XDECREF(traceback);
519544520545Py_XDECREF(oldtype);
521546Py_XDECREF(oldvalue);
@@ -527,22 +552,19 @@ PyObject*
527552_PyErr_StackItemToExcInfoTuple(_PyErr_StackItem *err_info)
528553{
529554PyObject *exc_value = err_info->exc_value;
530-if (exc_value == NULL) {
531-exc_value = Py_None;
532- }
533555534-assert(exc_value == Py_None || PyExceptionInstance_Check(exc_value));
556+assert(exc_value == NULL ||
557+exc_value == Py_None ||
558+PyExceptionInstance_Check(exc_value));
535559536-PyObject *exc_type = PyExceptionInstance_Check(exc_value) ?
537-PyExceptionInstance_Class(exc_value) :
538-Py_None;
560+PyObject *exc_type = get_exc_type(exc_value);
561+PyObject *exc_traceback = get_exc_traceback(exc_value);
539562540563return Py_BuildValue(
541564"(OOO)",
542-exc_type,
543-exc_value,
544-err_info->exc_traceback != NULL ?
545-err_info->exc_traceback : Py_None);
565+exc_type ? exc_type : Py_None,
566+exc_value ? exc_value : Py_None,
567+exc_traceback ? exc_traceback : Py_None);
546568}
547569548570