static void CHAIN_EXCEPTION( PyObject *exception_type, PyObject *exception_value ) { // Implicit chain of exception already existing. PyThreadState *thread_state = PyThreadState_GET(); // Normalize existing exception first. PyErr_NormalizeException( &thread_state->exc_type, &thread_state->exc_value, &thread_state->exc_traceback ); PyObject *old_exc_value = thread_state->exc_value; if ( old_exc_value != NULL && old_exc_value != Py_None && old_exc_value != exception_value ) { Py_INCREF( old_exc_value ); PyObject *o = old_exc_value, *context; while (( context = PyException_GetContext(o) )) { Py_DECREF( context ); if ( context == exception_value ) { PyException_SetContext( o, NULL ); break; } o = context; } PyException_SetContext( exception_value, old_exc_value ); PyException_SetTraceback( old_exc_value, thread_state->exc_traceback ); } }
static void print_exception_recursive(PyObject *f, PyObject *value, PyObject *seen) { int err = 0, res; PyObject *cause, *context; if (seen != NULL) { /* Exception chaining */ PyObject *value_id = PyLong_FromVoidPtr(value); if (value_id == NULL || PySet_Add(seen, value_id) == -1) PyErr_Clear(); else if (PyExceptionInstance_Check(value)) { PyObject *check_id = NULL; cause = PyException_GetCause(value); context = PyException_GetContext(value); if (cause) { check_id = PyLong_FromVoidPtr(cause); if (check_id == NULL) { res = -1; } else { res = PySet_Contains(seen, check_id); Py_DECREF(check_id); } if (res == -1) PyErr_Clear(); if (res == 0) { print_exception_recursive( f, cause, seen); err |= PyFile_WriteString( cause_message, f); } } else if (context && !((PyBaseExceptionObject *)value)->suppress_context) { check_id = PyLong_FromVoidPtr(context); if (check_id == NULL) { res = -1; } else { res = PySet_Contains(seen, check_id); Py_DECREF(check_id); } if (res == -1) PyErr_Clear(); if (res == 0) { print_exception_recursive( f, context, seen); err |= PyFile_WriteString( context_message, f); } } Py_XDECREF(context); Py_XDECREF(cause); } Py_XDECREF(value_id); } print_exception(f, value); if (err != 0) PyErr_Clear(); }
static void CHAIN_EXCEPTION( PyObject *exception_type, PyObject *exception_value ) { // Implicit chain of exception already existing. PyThreadState *thread_state = PyThreadState_GET(); // Normalize existing exception first. TODO: Will normally be done already. NORMALIZE_EXCEPTION( &thread_state->exc_type, &thread_state->exc_value, (PyTracebackObject **)&thread_state->exc_traceback ); PyObject *old_exc_value = thread_state->exc_value; if ( old_exc_value != NULL && old_exc_value != Py_None && old_exc_value != exception_value ) { PyObject *current = old_exc_value; while( true ) { PyObject *context = PyException_GetContext( current ); if (!context) break; CHECK_OBJECT( context ); Py_DECREF( context ); CHECK_OBJECT( context ); if ( context == exception_value ) { PyException_SetContext( current, NULL ); break; } current = context; } CHECK_OBJECT( old_exc_value ); Py_INCREF( old_exc_value ); PyException_SetContext( exception_value, old_exc_value ); CHECK_OBJECT( thread_state->exc_traceback ); PyException_SetTraceback( old_exc_value, thread_state->exc_traceback ); } }
void PyErr_SetObject(PyObject *exception, PyObject *value) { PyThreadState *tstate = PyThreadState_GET(); PyObject *exc_value; PyObject *tb = NULL; if (exception != NULL && !PyExceptionClass_Check(exception)) { PyErr_Format(PyExc_SystemError, "exception %R not a BaseException subclass", exception); return; } Py_XINCREF(value); exc_value = tstate->exc_value; if (exc_value != NULL && exc_value != Py_None) { /* Implicit exception chaining */ Py_INCREF(exc_value); if (value == NULL || !PyExceptionInstance_Check(value)) { /* We must normalize the value right now */ PyObject *fixed_value; /* Issue #23571: functions must not be called with an exception set */ PyErr_Clear(); fixed_value = _PyErr_CreateException(exception, value); Py_XDECREF(value); if (fixed_value == NULL) { return; } value = fixed_value; } /* Avoid reference cycles through the context chain. This is O(chain length) but context chains are usually very short. Sensitive readers may try to inline the call to PyException_GetContext. */ if (exc_value != value) { PyObject *o = exc_value, *context; while ((context = PyException_GetContext(o))) { Py_DECREF(context); if (context == value) { PyException_SetContext(o, NULL); break; } o = context; } PyException_SetContext(value, exc_value); } else { Py_DECREF(exc_value); } } if (value != NULL && PyExceptionInstance_Check(value)) tb = PyException_GetTraceback(value); Py_XINCREF(exception); PyErr_Restore(exception, value, tb); }