/* Error handling */ #include "Python.h" #include "pycore_pystate.h" #ifndef __STDC__ #ifndef MS_WINDOWS extern char *strerror(int); #endif #endif #ifdef MS_WINDOWS #include #include #endif #include #ifdef __cplusplus extern "C" { #endif _Py_IDENTIFIER(builtins); _Py_IDENTIFIER(stderr); void PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *oldtype, *oldvalue, *oldtraceback; if (traceback != NULL && !PyTraceBack_Check(traceback)) { /* XXX Should never happen -- fatal error instead? */ /* Well, it could be None. */ Py_DECREF(traceback); traceback = NULL; } /* Save these in locals to safeguard against recursive invocation through Py_XDECREF */ oldtype = tstate->curexc_type; oldvalue = tstate->curexc_value; oldtraceback = tstate->curexc_traceback; tstate->curexc_type = type; tstate->curexc_value = value; tstate->curexc_traceback = traceback; Py_XDECREF(oldtype); Py_XDECREF(oldvalue); Py_XDECREF(oldtraceback); } _PyErr_StackItem * _PyErr_GetTopmostException(PyThreadState *tstate) { _PyErr_StackItem *exc_info = tstate->exc_info; while ((exc_info->exc_type == NULL || exc_info->exc_type == Py_None) && exc_info->previous_item != NULL) { exc_info = exc_info->previous_item; } return exc_info; } static PyObject* _PyErr_CreateException(PyObject *exception, PyObject *value) { if (value == NULL || value == Py_None) { return _PyObject_CallNoArg(exception); } else if (PyTuple_Check(value)) { return PyObject_Call(exception, value, NULL); } else { return PyObject_CallFunctionObjArgs(exception, value, NULL); } } 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 = _PyErr_GetTopmostException(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) { Py_DECREF(exc_value); 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); } /* Set a key error with the specified argument, wrapping it in a * tuple automatically so that tuple keys are not unpacked as the * exception arguments. */ void _PyErr_SetKeyError(PyObject *arg) { PyObject *tup; tup = PyTuple_Pack(1, arg); if (!tup) return; /* caller will expect error to be set anyway */ PyErr_SetObject(PyExc_KeyError, tup); Py_DECREF(tup); } void PyErr_SetNone(PyObject *exception) { PyErr_SetObject(exception, (PyObject *)NULL); } void PyErr_SetString(PyObject *exception, const char *string) { PyObject *value = PyUnicode_FromString(string); PyErr_SetObject(exception, value); Py_XDECREF(value); } PyObject* _Py_HOT_FUNCTION PyErr_Occurred(void) { PyThreadState *tstate = _PyThreadState_GET(); return tstate == NULL ? NULL : tstate->curexc_type; } int PyErr_GivenExceptionMatches(PyObject *err, PyObject *exc) { if (err == NULL || exc == NULL) { /* maybe caused by "import exceptions" that failed early on */ return 0; } if (PyTuple_Check(exc)) { Py_ssize_t i, n; n = PyTuple_Size(exc); for (i = 0; i < n; i++) { /* Test recursively */ if (PyErr_GivenExceptionMatches( err, PyTuple_GET_ITEM(exc, i))) { return 1; } } return 0; } /* err might be an instance, so check its class. */ if (PyExceptionInstance_Check(err)) err = PyExceptionInstance_Class(err); if (PyExceptionClass_Check(err) && PyExceptionClass_Check(exc)) { return PyType_IsSubtype((PyTypeObject *)err, (PyTypeObject *)exc); } return err == exc; } int PyErr_ExceptionMatches(PyObject *exc) { return PyErr_GivenExceptionMatches(PyErr_Occurred(), exc); } #ifndef Py_NORMALIZE_RECURSION_LIMIT #define Py_NORMALIZE_RECURSION_LIMIT 32 #endif /* Used in many places to normalize a raised exception, including in eval_code2(), do_raise(), and PyErr_Print() XXX: should PyErr_NormalizeException() also call PyException_SetTraceback() with the resulting value and tb? */ void PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb) { int recursion_depth = 0; PyObject *type, *value, *initial_tb; restart: type = *exc; if (type == NULL) { /* There was no exception, so nothing to do. */ return; } value = *val; /* If PyErr_SetNone() was used, the value will have been actually set to NULL. */ if (!value) { value = Py_None; Py_INCREF(value); } /* Normalize the exception so that if the type is a class, the value will be an instance. */ if (PyExceptionClass_Check(type)) { PyObject *inclass = NULL; int is_subclass = 0; if (PyExceptionInstance_Check(value)) { inclass = PyExceptionInstance_Class(value); is_subclass = PyObject_IsSubclass(inclass, type); if (is_subclass < 0) { goto error; } } /* If the value was not an instance, or is not an instance whose class is (or is derived from) type, then use the value as an argument to instantiation of the type class. */ if (!is_subclass) { PyObject *fixed_value = _PyErr_CreateException(type, value); if (fixed_value == NULL) { goto error; } Py_DECREF(value); value = fixed_value; } /* If the class of the instance doesn't exactly match the class of the type, believe the instance. */ else if (inclass != type) { Py_INCREF(inclass); Py_DECREF(type);