summaryrefslogtreecommitdiff
path: root/Python/errors.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/errors.c')
-rw-r--r--Python/errors.c144
1 files changed, 97 insertions, 47 deletions
diff --git a/Python/errors.c b/Python/errors.c
index 6cc0c20cd5..918f4dffab 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -52,6 +52,20 @@ PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback)
Py_XDECREF(oldtraceback);
}
+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_CallArg1(exception, value);
+ }
+}
+
void
PyErr_SetObject(PyObject *exception, PyObject *value)
{
@@ -66,6 +80,7 @@ PyErr_SetObject(PyObject *exception, PyObject *value)
exception);
return;
}
+
Py_XINCREF(value);
exc_value = tstate->exc_value;
if (exc_value != NULL && exc_value != Py_None) {
@@ -73,28 +88,21 @@ PyErr_SetObject(PyObject *exception, PyObject *value)
Py_INCREF(exc_value);
if (value == NULL || !PyExceptionInstance_Check(value)) {
/* We must normalize the value right now */
- PyObject *args, *fixed_value;
+ PyObject *fixed_value;
- /* Issue #23571: PyEval_CallObject() must not be called with an
+ /* Issue #23571: functions must not be called with an
exception set */
PyErr_Clear();
- if (value == NULL || value == Py_None)
- args = PyTuple_New(0);
- else if (PyTuple_Check(value)) {
- Py_INCREF(value);
- args = value;
- }
- else
- args = PyTuple_Pack(1, value);
- fixed_value = args ?
- PyEval_CallObject(exception, args) : NULL;
- Py_XDECREF(args);
+ fixed_value = _PyErr_CreateException(exception, value);
Py_XDECREF(value);
- if (fixed_value == NULL)
+ 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
@@ -110,7 +118,8 @@ PyErr_SetObject(PyObject *exception, PyObject *value)
o = context;
}
PyException_SetContext(value, exc_value);
- } else {
+ }
+ else {
Py_DECREF(exc_value);
}
}
@@ -258,25 +267,15 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
class.
*/
if (!inclass || !is_subclass) {
- PyObject *args, *res;
+ PyObject *fixed_value;
- if (value == Py_None)
- args = PyTuple_New(0);
- else if (PyTuple_Check(value)) {
- Py_INCREF(value);
- args = value;
+ fixed_value = _PyErr_CreateException(type, value);
+ if (fixed_value == NULL) {
+ goto finally;
}
- else
- args = PyTuple_Pack(1, value);
- if (args == NULL)
- goto finally;
- res = PyEval_CallObject(type, args);
- Py_DECREF(args);
- if (res == NULL)
- goto finally;
Py_DECREF(value);
- value = res;
+ value = fixed_value;
}
/* if the class of the instance doesn't exactly match the
class of the type, believe the instance
@@ -402,6 +401,47 @@ _PyErr_ChainExceptions(PyObject *exc, PyObject *val, PyObject *tb)
}
}
+static PyObject *
+_PyErr_FormatVFromCause(PyObject *exception, const char *format, va_list vargs)
+{
+ PyObject *exc, *val, *val2, *tb;
+
+ assert(PyErr_Occurred());
+ PyErr_Fetch(&exc, &val, &tb);
+ PyErr_NormalizeException(&exc, &val, &tb);
+ if (tb != NULL) {
+ PyException_SetTraceback(val, tb);
+ Py_DECREF(tb);
+ }
+ Py_DECREF(exc);
+ assert(!PyErr_Occurred());
+
+ PyErr_FormatV(exception, format, vargs);
+
+ PyErr_Fetch(&exc, &val2, &tb);
+ PyErr_NormalizeException(&exc, &val2, &tb);
+ Py_INCREF(val);
+ PyException_SetCause(val2, val);
+ PyException_SetContext(val2, val);
+ PyErr_Restore(exc, val2, tb);
+
+ return NULL;
+}
+
+PyObject *
+_PyErr_FormatFromCause(PyObject *exception, const char *format, ...)
+{
+ va_list vargs;
+#ifdef HAVE_STDARG_PROTOTYPES
+ va_start(vargs, format);
+#else
+ va_start(vargs);
+#endif
+ _PyErr_FormatVFromCause(exception, format, vargs);
+ va_end(vargs);
+ return NULL;
+}
+
/* Convenience functions to set a type error exception and return 0 */
int
@@ -701,51 +741,61 @@ PyObject *PyErr_SetFromWindowsErrWithUnicodeFilename(
#endif /* MS_WINDOWS */
PyObject *
-PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path)
+PyErr_SetImportErrorSubclass(PyObject *exception, PyObject *msg,
+ PyObject *name, PyObject *path)
{
- PyObject *args, *kwargs, *error;
+ int issubclass;
+ PyObject *kwargs, *error;
- if (msg == NULL)
+ issubclass = PyObject_IsSubclass(exception, PyExc_ImportError);
+ if (issubclass < 0) {
return NULL;
-
- args = PyTuple_New(1);
- if (args == NULL)
+ }
+ else if (!issubclass) {
+ PyErr_SetString(PyExc_TypeError, "expected a subclass of ImportError");
return NULL;
+ }
- kwargs = PyDict_New();
- if (kwargs == NULL) {
- Py_DECREF(args);
+ if (msg == NULL) {
+ PyErr_SetString(PyExc_TypeError, "expected a message argument");
return NULL;
}
if (name == NULL) {
name = Py_None;
}
-
if (path == NULL) {
path = Py_None;
}
- Py_INCREF(msg);
- PyTuple_SET_ITEM(args, 0, msg);
-
- if (PyDict_SetItemString(kwargs, "name", name) < 0)
+ kwargs = PyDict_New();
+ if (kwargs == NULL) {
+ return NULL;
+ }
+ if (PyDict_SetItemString(kwargs, "name", name) < 0) {
goto done;
- if (PyDict_SetItemString(kwargs, "path", path) < 0)
+ }
+ if (PyDict_SetItemString(kwargs, "path", path) < 0) {
goto done;
+ }
- error = PyObject_Call(PyExc_ImportError, args, kwargs);
+ error = _PyObject_FastCallDict(exception, &msg, 1, kwargs);
if (error != NULL) {
PyErr_SetObject((PyObject *)Py_TYPE(error), error);
Py_DECREF(error);
}
done:
- Py_DECREF(args);
Py_DECREF(kwargs);
return NULL;
}
+PyObject *
+PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path)
+{
+ return PyErr_SetImportErrorSubclass(PyExc_ImportError, msg, name, path);
+}
+
void
_PyErr_BadInternalCall(const char *filename, int lineno)
{