mirror of https://github.com/python/cpython
GH-101578: Normalize the current exception (GH-101607)
* Make sure that the current exception is always normalized. * Remove redundant type and traceback fields for the current exception. * Add new API functions: PyErr_GetRaisedException, PyErr_SetRaisedException * Add new API functions: PyException_GetArgs, PyException_SetArgs
This commit is contained in:
parent
027adf42cd
commit
feec49c407
|
@ -400,8 +400,61 @@ Querying the error indicator
|
|||
recursively in subtuples) are searched for a match.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyErr_GetRaisedException(void)
|
||||
|
||||
Returns the exception currently being raised, clearing the exception at
|
||||
the same time. Do not confuse this with the exception currently being
|
||||
handled which can be accessed with :c:func:`PyErr_GetHandledException`.
|
||||
|
||||
.. note::
|
||||
|
||||
This function is normally only used by code that needs to catch exceptions or
|
||||
by code that needs to save and restore the error indicator temporarily, e.g.::
|
||||
|
||||
{
|
||||
PyObject *exc = PyErr_GetRaisedException();
|
||||
|
||||
/* ... code that might produce other errors ... */
|
||||
|
||||
PyErr_SetRaisedException(exc);
|
||||
}
|
||||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
|
||||
.. c:function:: void PyErr_SetRaisedException(PyObject *exc)
|
||||
|
||||
Sets the exception currently being raised ``exc``.
|
||||
If the exception is already set, it is cleared first.
|
||||
|
||||
``exc`` must be a valid exception.
|
||||
(Violating this rules will cause subtle problems later.)
|
||||
This call consumes a reference to the ``exc`` object: you must own a
|
||||
reference to that object before the call and after the call you no longer own
|
||||
that reference.
|
||||
(If you don't understand this, don't use this function. I warned you.)
|
||||
|
||||
.. note::
|
||||
|
||||
This function is normally only used by code that needs to save and restore the
|
||||
error indicator temporarily. Use :c:func:`PyErr_GetRaisedException` to save
|
||||
the current exception, e.g.::
|
||||
|
||||
{
|
||||
PyObject *exc = PyErr_GetRaisedException();
|
||||
|
||||
/* ... code that might produce other errors ... */
|
||||
|
||||
PyErr_SetRaisedException(exc);
|
||||
}
|
||||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
|
||||
.. c:function:: void PyErr_Fetch(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback)
|
||||
|
||||
As of 3.12, this function is deprecated. Use :c:func:`PyErr_GetRaisedException` instead.
|
||||
|
||||
Retrieve the error indicator into three variables whose addresses are passed.
|
||||
If the error indicator is not set, set all three variables to ``NULL``. If it is
|
||||
set, it will be cleared and you own a reference to each object retrieved. The
|
||||
|
@ -421,9 +474,13 @@ Querying the error indicator
|
|||
PyErr_Restore(type, value, traceback);
|
||||
}
|
||||
|
||||
.. deprecated:: 3.12
|
||||
|
||||
|
||||
.. c:function:: void PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback)
|
||||
|
||||
As of 3.12, this function is deprecated. Use :c:func:`PyErr_SetRaisedException` instead.
|
||||
|
||||
Set the error indicator from the three objects. If the error indicator is
|
||||
already set, it is cleared first. If the objects are ``NULL``, the error
|
||||
indicator is cleared. Do not pass a ``NULL`` type and non-``NULL`` value or
|
||||
|
@ -440,9 +497,15 @@ Querying the error indicator
|
|||
error indicator temporarily. Use :c:func:`PyErr_Fetch` to save the current
|
||||
error indicator.
|
||||
|
||||
.. deprecated:: 3.12
|
||||
|
||||
|
||||
.. c:function:: void PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
|
||||
|
||||
As of 3.12, this function is deprecated.
|
||||
Use :c:func:`PyErr_GetRaisedException` instead of :c:func:`PyErr_Fetch` to avoid
|
||||
any possible de-normalization.
|
||||
|
||||
Under certain circumstances, the values returned by :c:func:`PyErr_Fetch` below
|
||||
can be "unnormalized", meaning that ``*exc`` is a class object but ``*val`` is
|
||||
not an instance of the same class. This function can be used to instantiate
|
||||
|
@ -459,6 +522,8 @@ Querying the error indicator
|
|||
PyException_SetTraceback(val, tb);
|
||||
}
|
||||
|
||||
.. deprecated:: 3.12
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyErr_GetHandledException(void)
|
||||
|
||||
|
@ -704,6 +769,18 @@ Exception Objects
|
|||
:attr:`__suppress_context__` is implicitly set to ``True`` by this function.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyException_GetArgs(PyObject *ex)
|
||||
|
||||
Return args of the given exception as a new reference,
|
||||
as accessible from Python through :attr:`args`.
|
||||
|
||||
|
||||
.. c:function:: void PyException_SetArgs(PyObject *ex, PyObject *args)
|
||||
|
||||
Set the args of the given exception,
|
||||
as accessible from Python through :attr:`args`.
|
||||
|
||||
|
||||
.. _unicodeexceptions:
|
||||
|
||||
Unicode Exception Objects
|
||||
|
|
|
@ -139,6 +139,7 @@ function,PyErr_Format,3.2,,
|
|||
function,PyErr_FormatV,3.5,,
|
||||
function,PyErr_GetExcInfo,3.7,,
|
||||
function,PyErr_GetHandledException,3.11,,
|
||||
function,PyErr_GetRaisedException,3.12,,
|
||||
function,PyErr_GivenExceptionMatches,3.2,,
|
||||
function,PyErr_NewException,3.2,,
|
||||
function,PyErr_NewExceptionWithDoc,3.2,,
|
||||
|
@ -168,6 +169,7 @@ function,PyErr_SetInterrupt,3.2,,
|
|||
function,PyErr_SetInterruptEx,3.10,,
|
||||
function,PyErr_SetNone,3.2,,
|
||||
function,PyErr_SetObject,3.2,,
|
||||
function,PyErr_SetRaisedException,3.12,,
|
||||
function,PyErr_SetString,3.2,,
|
||||
function,PyErr_SyntaxLocation,3.2,,
|
||||
function,PyErr_SyntaxLocationEx,3.7,,
|
||||
|
@ -266,9 +268,11 @@ var,PyExc_Warning,3.2,,
|
|||
var,PyExc_WindowsError,3.7,on Windows,
|
||||
var,PyExc_ZeroDivisionError,3.2,,
|
||||
function,PyExceptionClass_Name,3.8,,
|
||||
function,PyException_GetArgs,3.12,,
|
||||
function,PyException_GetCause,3.2,,
|
||||
function,PyException_GetContext,3.2,,
|
||||
function,PyException_GetTraceback,3.2,,
|
||||
function,PyException_SetArgs,3.12,,
|
||||
function,PyException_SetCause,3.2,,
|
||||
function,PyException_SetContext,3.2,,
|
||||
function,PyException_SetTraceback,3.2,,
|
||||
|
|
|
@ -99,6 +99,7 @@ PyAPI_FUNC(void) _PyErr_GetExcInfo(PyThreadState *, PyObject **, PyObject **, Py
|
|||
/* Context manipulation (PEP 3134) */
|
||||
|
||||
PyAPI_FUNC(void) _PyErr_ChainExceptions(PyObject *, PyObject *, PyObject *);
|
||||
PyAPI_FUNC(void) _PyErr_ChainExceptions1(PyObject *);
|
||||
|
||||
/* Like PyErr_Format(), but saves current exception as __context__ and
|
||||
__cause__.
|
||||
|
|
|
@ -166,9 +166,7 @@ struct _ts {
|
|||
PyObject *c_traceobj;
|
||||
|
||||
/* The exception currently being raised */
|
||||
PyObject *curexc_type;
|
||||
PyObject *curexc_value;
|
||||
PyObject *curexc_traceback;
|
||||
PyObject *current_exception;
|
||||
|
||||
/* Pointer to the top of the exception stack for the exceptions
|
||||
* we may be currently handling. (See _PyErr_StackItem above.)
|
||||
|
|
|
@ -20,7 +20,10 @@ extern void _PyErr_FiniTypes(PyInterpreterState *);
|
|||
static inline PyObject* _PyErr_Occurred(PyThreadState *tstate)
|
||||
{
|
||||
assert(tstate != NULL);
|
||||
return tstate->curexc_type;
|
||||
if (tstate->current_exception == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return (PyObject *)Py_TYPE(tstate->current_exception);
|
||||
}
|
||||
|
||||
static inline void _PyErr_ClearExcState(_PyErr_StackItem *exc_state)
|
||||
|
@ -37,10 +40,16 @@ PyAPI_FUNC(void) _PyErr_Fetch(
|
|||
PyObject **value,
|
||||
PyObject **traceback);
|
||||
|
||||
extern PyObject *
|
||||
_PyErr_GetRaisedException(PyThreadState *tstate);
|
||||
|
||||
PyAPI_FUNC(int) _PyErr_ExceptionMatches(
|
||||
PyThreadState *tstate,
|
||||
PyObject *exc);
|
||||
|
||||
void
|
||||
_PyErr_SetRaisedException(PyThreadState *tstate, PyObject *exc);
|
||||
|
||||
PyAPI_FUNC(void) _PyErr_Restore(
|
||||
PyThreadState *tstate,
|
||||
PyObject *type,
|
||||
|
|
|
@ -18,6 +18,8 @@ PyAPI_FUNC(PyObject *) PyErr_Occurred(void);
|
|||
PyAPI_FUNC(void) PyErr_Clear(void);
|
||||
PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **);
|
||||
PyAPI_FUNC(void) PyErr_Restore(PyObject *, PyObject *, PyObject *);
|
||||
PyAPI_FUNC(PyObject *) PyErr_GetRaisedException(void);
|
||||
PyAPI_FUNC(void) PyErr_SetRaisedException(PyObject *);
|
||||
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030b0000
|
||||
PyAPI_FUNC(PyObject*) PyErr_GetHandledException(void);
|
||||
PyAPI_FUNC(void) PyErr_SetHandledException(PyObject *);
|
||||
|
@ -51,6 +53,10 @@ PyAPI_FUNC(void) PyException_SetCause(PyObject *, PyObject *);
|
|||
PyAPI_FUNC(PyObject *) PyException_GetContext(PyObject *);
|
||||
PyAPI_FUNC(void) PyException_SetContext(PyObject *, PyObject *);
|
||||
|
||||
|
||||
PyAPI_FUNC(PyObject *) PyException_GetArgs(PyObject *);
|
||||
PyAPI_FUNC(void) PyException_SetArgs(PyObject *, PyObject *);
|
||||
|
||||
/* */
|
||||
|
||||
#define PyExceptionClass_Check(x) \
|
||||
|
|
|
@ -1553,5 +1553,44 @@ class Test_Pep523API(unittest.TestCase):
|
|||
self.do_test(func2)
|
||||
|
||||
|
||||
class Test_ErrSetAndRestore(unittest.TestCase):
|
||||
|
||||
def test_err_set_raised(self):
|
||||
with self.assertRaises(ValueError):
|
||||
_testcapi.err_set_raised(ValueError())
|
||||
v = ValueError()
|
||||
try:
|
||||
_testcapi.err_set_raised(v)
|
||||
except ValueError as ex:
|
||||
self.assertIs(v, ex)
|
||||
|
||||
def test_err_restore(self):
|
||||
with self.assertRaises(ValueError):
|
||||
_testcapi.err_restore(ValueError)
|
||||
with self.assertRaises(ValueError):
|
||||
_testcapi.err_restore(ValueError, 1)
|
||||
with self.assertRaises(ValueError):
|
||||
_testcapi.err_restore(ValueError, 1, None)
|
||||
with self.assertRaises(ValueError):
|
||||
_testcapi.err_restore(ValueError, ValueError())
|
||||
try:
|
||||
_testcapi.err_restore(KeyError, "hi")
|
||||
except KeyError as k:
|
||||
self.assertEqual("hi", k.args[0])
|
||||
try:
|
||||
1/0
|
||||
except Exception as e:
|
||||
tb = e.__traceback__
|
||||
with self.assertRaises(ValueError):
|
||||
_testcapi.err_restore(ValueError, 1, tb)
|
||||
with self.assertRaises(TypeError):
|
||||
_testcapi.err_restore(ValueError, 1, 0)
|
||||
try:
|
||||
_testcapi.err_restore(ValueError, 1, tb)
|
||||
except ValueError as v:
|
||||
self.assertEqual(1, v.args[0])
|
||||
self.assertIs(tb, v.__traceback__.tb_next)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -347,6 +347,7 @@ class ExceptionTests(unittest.TestCase):
|
|||
_testcapi.raise_exception(BadException, 0)
|
||||
except RuntimeError as err:
|
||||
exc, err, tb = sys.exc_info()
|
||||
tb = tb.tb_next
|
||||
co = tb.tb_frame.f_code
|
||||
self.assertEqual(co.co_name, "__init__")
|
||||
self.assertTrue(co.co_filename.endswith('test_exceptions.py'))
|
||||
|
@ -1415,8 +1416,8 @@ class ExceptionTests(unittest.TestCase):
|
|||
@cpython_only
|
||||
def test_recursion_normalizing_infinite_exception(self):
|
||||
# Issue #30697. Test that a RecursionError is raised when
|
||||
# PyErr_NormalizeException() maximum recursion depth has been
|
||||
# exceeded.
|
||||
# maximum recursion depth has been exceeded when creating
|
||||
# an exception
|
||||
code = """if 1:
|
||||
import _testcapi
|
||||
try:
|
||||
|
@ -1426,8 +1427,7 @@ class ExceptionTests(unittest.TestCase):
|
|||
"""
|
||||
rc, out, err = script_helper.assert_python_failure("-c", code)
|
||||
self.assertEqual(rc, 1)
|
||||
self.assertIn(b'RecursionError: maximum recursion depth exceeded '
|
||||
b'while normalizing an exception', err)
|
||||
self.assertIn(b'RecursionError: maximum recursion depth exceeded', err)
|
||||
self.assertIn(b'Done.', out)
|
||||
|
||||
|
||||
|
|
|
@ -172,6 +172,7 @@ SYMBOL_NAMES = (
|
|||
"PyErr_FormatV",
|
||||
"PyErr_GetExcInfo",
|
||||
"PyErr_GetHandledException",
|
||||
"PyErr_GetRaisedException",
|
||||
"PyErr_GivenExceptionMatches",
|
||||
"PyErr_NewException",
|
||||
"PyErr_NewExceptionWithDoc",
|
||||
|
@ -195,6 +196,7 @@ SYMBOL_NAMES = (
|
|||
"PyErr_SetInterruptEx",
|
||||
"PyErr_SetNone",
|
||||
"PyErr_SetObject",
|
||||
"PyErr_SetRaisedException",
|
||||
"PyErr_SetString",
|
||||
"PyErr_SyntaxLocation",
|
||||
"PyErr_SyntaxLocationEx",
|
||||
|
@ -292,9 +294,11 @@ SYMBOL_NAMES = (
|
|||
"PyExc_Warning",
|
||||
"PyExc_ZeroDivisionError",
|
||||
"PyExceptionClass_Name",
|
||||
"PyException_GetArgs",
|
||||
"PyException_GetCause",
|
||||
"PyException_GetContext",
|
||||
"PyException_GetTraceback",
|
||||
"PyException_SetArgs",
|
||||
"PyException_SetCause",
|
||||
"PyException_SetContext",
|
||||
"PyException_SetTraceback",
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
Add new C-API functions for saving and restoring the current exception:
|
||||
``PyErr_GetRaisedException`` and ``PyErr_SetRaisedException``.
|
||||
These functions take and return a single exception rather than
|
||||
the triple of ``PyErr_Fetch`` and ``PyErr_Restore``.
|
||||
This is less error prone and a bit more efficient.
|
||||
|
||||
The three arguments forms of saving and restoring the
|
||||
current exception: ``PyErr_Fetch`` and ``PyErr_Restore``
|
||||
are deprecated.
|
||||
|
||||
Also add ``PyException_GetArgs`` and ``PyException_SetArgs``
|
||||
as convenience functions to help dealing with
|
||||
exceptions in the C API.
|
|
@ -2333,6 +2333,15 @@
|
|||
added = '3.12'
|
||||
[function.PyVectorcall_Call]
|
||||
added = '3.12'
|
||||
[function.PyErr_GetRaisedException]
|
||||
added = '3.12'
|
||||
[function.PyErr_SetRaisedException]
|
||||
added = '3.12'
|
||||
[function.PyException_GetArgs]
|
||||
added = '3.12'
|
||||
[function.PyException_SetArgs]
|
||||
added = '3.12'
|
||||
|
||||
[typedef.vectorcallfunc]
|
||||
added = '3.12'
|
||||
[function.PyObject_Vectorcall]
|
||||
|
|
|
@ -116,10 +116,10 @@ test_from_spec_invalid_metatype_inheritance(PyObject *self, PyObject *Py_UNUSED(
|
|||
PyObject *bases = NULL;
|
||||
PyObject *new = NULL;
|
||||
PyObject *meta_error_string = NULL;
|
||||
PyObject *exc_type = NULL;
|
||||
PyObject *exc_value = NULL;
|
||||
PyObject *exc_traceback = NULL;
|
||||
PyObject *exc = NULL;
|
||||
PyObject *result = NULL;
|
||||
PyObject *message = NULL;
|
||||
PyObject *args = NULL;
|
||||
|
||||
metaclass_a = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
|
||||
if (metaclass_a == NULL) {
|
||||
|
@ -156,13 +156,19 @@ test_from_spec_invalid_metatype_inheritance(PyObject *self, PyObject *Py_UNUSED(
|
|||
|
||||
// Assert that the correct exception was raised
|
||||
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
|
||||
PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
|
||||
|
||||
exc = PyErr_GetRaisedException();
|
||||
args = PyException_GetArgs(exc);
|
||||
if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) {
|
||||
PyErr_SetString(PyExc_AssertionError,
|
||||
"TypeError args are not a one-tuple");
|
||||
goto finally;
|
||||
}
|
||||
message = Py_NewRef(PyTuple_GET_ITEM(args, 0));
|
||||
meta_error_string = PyUnicode_FromString("metaclass conflict:");
|
||||
if (meta_error_string == NULL) {
|
||||
goto finally;
|
||||
}
|
||||
int res = PyUnicode_Contains(exc_value, meta_error_string);
|
||||
int res = PyUnicode_Contains(message, meta_error_string);
|
||||
if (res < 0) {
|
||||
goto finally;
|
||||
}
|
||||
|
@ -179,11 +185,11 @@ finally:
|
|||
Py_XDECREF(bases);
|
||||
Py_XDECREF(new);
|
||||
Py_XDECREF(meta_error_string);
|
||||
Py_XDECREF(exc_type);
|
||||
Py_XDECREF(exc_value);
|
||||
Py_XDECREF(exc_traceback);
|
||||
Py_XDECREF(exc);
|
||||
Py_XDECREF(message);
|
||||
Py_XDECREF(class_a);
|
||||
Py_XDECREF(class_b);
|
||||
Py_XDECREF(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -3470,6 +3470,41 @@ function_set_kw_defaults(PyObject *self, PyObject *args)
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
err_set_raised(PyObject *self, PyObject *exc)
|
||||
{
|
||||
Py_INCREF(exc);
|
||||
PyErr_SetRaisedException(exc);
|
||||
assert(PyErr_Occurred());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
err_restore(PyObject *self, PyObject *args) {
|
||||
PyObject *type = NULL, *value = NULL, *traceback = NULL;
|
||||
switch(PyTuple_Size(args)) {
|
||||
case 3:
|
||||
traceback = PyTuple_GetItem(args, 2);
|
||||
Py_INCREF(traceback);
|
||||
/* fall through */
|
||||
case 2:
|
||||
value = PyTuple_GetItem(args, 1);
|
||||
Py_INCREF(value);
|
||||
/* fall through */
|
||||
case 1:
|
||||
type = PyTuple_GetItem(args, 0);
|
||||
Py_INCREF(type);
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"wrong number of arguments");
|
||||
return NULL;
|
||||
}
|
||||
PyErr_Restore(type, value, traceback);
|
||||
assert(PyErr_Occurred());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);
|
||||
|
||||
static PyMethodDef TestMethods[] = {
|
||||
|
@ -3622,6 +3657,8 @@ static PyMethodDef TestMethods[] = {
|
|||
{"function_set_defaults", function_set_defaults, METH_VARARGS, NULL},
|
||||
{"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL},
|
||||
{"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL},
|
||||
{"err_set_raised", err_set_raised, METH_O, NULL},
|
||||
{"err_restore", err_restore, METH_VARARGS, NULL},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
|
|
@ -2082,11 +2082,10 @@ PyGC_Collect(void)
|
|||
n = 0;
|
||||
}
|
||||
else {
|
||||
PyObject *exc, *value, *tb;
|
||||
gcstate->collecting = 1;
|
||||
_PyErr_Fetch(tstate, &exc, &value, &tb);
|
||||
PyObject *exc = _PyErr_GetRaisedException(tstate);
|
||||
n = gc_collect_with_callback(tstate, NUM_GENERATIONS - 1);
|
||||
_PyErr_Restore(tstate, exc, value, tb);
|
||||
_PyErr_SetRaisedException(tstate, exc);
|
||||
gcstate->collecting = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1663,15 +1663,15 @@ PyDict_GetItem(PyObject *op, PyObject *key)
|
|||
#endif
|
||||
|
||||
/* Preserve the existing exception */
|
||||
PyObject *exc_type, *exc_value, *exc_tb;
|
||||
PyObject *value;
|
||||
Py_ssize_t ix; (void)ix;
|
||||
|
||||
_PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb);
|
||||
|
||||
PyObject *exc = _PyErr_GetRaisedException(tstate);
|
||||
ix = _Py_dict_lookup(mp, key, hash, &value);
|
||||
|
||||
/* Ignore any exception raised by the lookup */
|
||||
_PyErr_Restore(tstate, exc_type, exc_value, exc_tb);
|
||||
_PyErr_SetRaisedException(tstate, exc);
|
||||
|
||||
|
||||
assert(ix >= 0 || value == NULL);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <Python.h>
|
||||
#include <stdbool.h>
|
||||
#include "pycore_ceval.h" // _Py_EnterRecursiveCall
|
||||
#include "pycore_pyerrors.h" // struct _PyErr_SetRaisedException
|
||||
#include "pycore_exceptions.h" // struct _Py_exc_state
|
||||
#include "pycore_initconfig.h"
|
||||
#include "pycore_object.h"
|
||||
|
@ -288,13 +289,17 @@ BaseException_set_tb(PyBaseExceptionObject *self, PyObject *tb, void *Py_UNUSED(
|
|||
PyErr_SetString(PyExc_TypeError, "__traceback__ may not be deleted");
|
||||
return -1;
|
||||
}
|
||||
else if (!(tb == Py_None || PyTraceBack_Check(tb))) {
|
||||
if (PyTraceBack_Check(tb)) {
|
||||
Py_XSETREF(self->traceback, Py_NewRef(tb));
|
||||
}
|
||||
else if (tb == Py_None) {
|
||||
Py_CLEAR(self->traceback);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"__traceback__ must be a traceback or None");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Py_XSETREF(self->traceback, Py_NewRef(tb));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -413,6 +418,20 @@ PyException_SetContext(PyObject *self, PyObject *context)
|
|||
Py_XSETREF(_PyBaseExceptionObject_cast(self)->context, context);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyException_GetArgs(PyObject *self)
|
||||
{
|
||||
PyObject *args = _PyBaseExceptionObject_cast(self)->args;
|
||||
return Py_NewRef(args);
|
||||
}
|
||||
|
||||
void
|
||||
PyException_SetArgs(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_INCREF(args);
|
||||
Py_XSETREF(_PyBaseExceptionObject_cast(self)->args, args);
|
||||
}
|
||||
|
||||
const char *
|
||||
PyExceptionClass_Name(PyObject *ob)
|
||||
{
|
||||
|
@ -3188,20 +3207,19 @@ SimpleExtendsException(PyExc_Exception, ReferenceError,
|
|||
|
||||
#define MEMERRORS_SAVE 16
|
||||
|
||||
static PyBaseExceptionObject last_resort_memory_error;
|
||||
|
||||
static PyObject *
|
||||
MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
get_memory_error(int allow_allocation, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyBaseExceptionObject *self;
|
||||
|
||||
/* If this is a subclass of MemoryError, don't use the freelist
|
||||
* and just return a fresh object */
|
||||
if (type != (PyTypeObject *) PyExc_MemoryError) {
|
||||
return BaseException_new(type, args, kwds);
|
||||
}
|
||||
|
||||
struct _Py_exc_state *state = get_exc_state();
|
||||
if (state->memerrors_freelist == NULL) {
|
||||
return BaseException_new(type, args, kwds);
|
||||
if (!allow_allocation) {
|
||||
return Py_NewRef(&last_resort_memory_error);
|
||||
}
|
||||
PyObject *result = BaseException_new((PyTypeObject *)PyExc_MemoryError, args, kwds);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Fetch object from freelist and revive it */
|
||||
|
@ -3221,6 +3239,35 @@ MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
static PyBaseExceptionObject last_resort_memory_error;
|
||||
|
||||
static PyObject *
|
||||
MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
/* If this is a subclass of MemoryError, don't use the freelist
|
||||
* and just return a fresh object */
|
||||
if (type != (PyTypeObject *) PyExc_MemoryError) {
|
||||
return BaseException_new(type, args, kwds);
|
||||
}
|
||||
return get_memory_error(1, args, kwds);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyErr_NoMemory(PyThreadState *tstate)
|
||||
{
|
||||
if (Py_IS_TYPE(PyExc_MemoryError, NULL)) {
|
||||
/* PyErr_NoMemory() has been called before PyExc_MemoryError has been
|
||||
initialized by _PyExc_Init() */
|
||||
Py_FatalError("Out of memory and PyExc_MemoryError is not "
|
||||
"initialized yet");
|
||||
}
|
||||
PyObject *err = get_memory_error(0, NULL, NULL);
|
||||
if (err != NULL) {
|
||||
_PyErr_SetRaisedException(tstate, err);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
MemoryError_dealloc(PyBaseExceptionObject *self)
|
||||
{
|
||||
|
@ -3252,6 +3299,7 @@ preallocate_memerrors(void)
|
|||
/* We create enough MemoryErrors and then decref them, which will fill
|
||||
up the freelist. */
|
||||
int i;
|
||||
|
||||
PyObject *errors[MEMERRORS_SAVE];
|
||||
for (i = 0; i < MEMERRORS_SAVE; i++) {
|
||||
errors[i] = MemoryError_new((PyTypeObject *) PyExc_MemoryError,
|
||||
|
@ -3291,6 +3339,9 @@ static PyTypeObject _PyExc_MemoryError = {
|
|||
};
|
||||
PyObject *PyExc_MemoryError = (PyObject *) &_PyExc_MemoryError;
|
||||
|
||||
static PyBaseExceptionObject last_resort_memory_error = {
|
||||
_PyObject_IMMORTAL_INIT(&_PyExc_MemoryError)
|
||||
};
|
||||
|
||||
/*
|
||||
* BufferError extends Exception
|
||||
|
|
|
@ -2416,10 +2416,10 @@ _Py_Dealloc(PyObject *op)
|
|||
destructor dealloc = type->tp_dealloc;
|
||||
#ifdef Py_DEBUG
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
PyObject *old_exc_type = tstate != NULL ? tstate->curexc_type : NULL;
|
||||
PyObject *old_exc = tstate != NULL ? tstate->current_exception : NULL;
|
||||
// Keep the old exception type alive to prevent undefined behavior
|
||||
// on (tstate->curexc_type != old_exc_type) below
|
||||
Py_XINCREF(old_exc_type);
|
||||
Py_XINCREF(old_exc);
|
||||
// Make sure that type->tp_name remains valid
|
||||
Py_INCREF(type);
|
||||
#endif
|
||||
|
@ -2432,12 +2432,12 @@ _Py_Dealloc(PyObject *op)
|
|||
#ifdef Py_DEBUG
|
||||
// gh-89373: The tp_dealloc function must leave the current exception
|
||||
// unchanged.
|
||||
if (tstate != NULL && tstate->curexc_type != old_exc_type) {
|
||||
if (tstate != NULL && tstate->current_exception != old_exc) {
|
||||
const char *err;
|
||||
if (old_exc_type == NULL) {
|
||||
if (old_exc == NULL) {
|
||||
err = "Deallocator of type '%s' raised an exception";
|
||||
}
|
||||
else if (tstate->curexc_type == NULL) {
|
||||
else if (tstate->current_exception == NULL) {
|
||||
err = "Deallocator of type '%s' cleared the current exception";
|
||||
}
|
||||
else {
|
||||
|
@ -2448,7 +2448,7 @@ _Py_Dealloc(PyObject *op)
|
|||
}
|
||||
_Py_FatalErrorFormat(__func__, err, type->tp_name);
|
||||
}
|
||||
Py_XDECREF(old_exc_type);
|
||||
Py_XDECREF(old_exc);
|
||||
Py_DECREF(type);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -198,6 +198,7 @@ EXPORT_FUNC(PyErr_Format)
|
|||
EXPORT_FUNC(PyErr_FormatV)
|
||||
EXPORT_FUNC(PyErr_GetExcInfo)
|
||||
EXPORT_FUNC(PyErr_GetHandledException)
|
||||
EXPORT_FUNC(PyErr_GetRaisedException)
|
||||
EXPORT_FUNC(PyErr_GivenExceptionMatches)
|
||||
EXPORT_FUNC(PyErr_NewException)
|
||||
EXPORT_FUNC(PyErr_NewExceptionWithDoc)
|
||||
|
@ -227,6 +228,7 @@ EXPORT_FUNC(PyErr_SetInterrupt)
|
|||
EXPORT_FUNC(PyErr_SetInterruptEx)
|
||||
EXPORT_FUNC(PyErr_SetNone)
|
||||
EXPORT_FUNC(PyErr_SetObject)
|
||||
EXPORT_FUNC(PyErr_SetRaisedException)
|
||||
EXPORT_FUNC(PyErr_SetString)
|
||||
EXPORT_FUNC(PyErr_SyntaxLocation)
|
||||
EXPORT_FUNC(PyErr_SyntaxLocationEx)
|
||||
|
@ -255,9 +257,11 @@ EXPORT_FUNC(PyEval_ReleaseThread)
|
|||
EXPORT_FUNC(PyEval_RestoreThread)
|
||||
EXPORT_FUNC(PyEval_SaveThread)
|
||||
EXPORT_FUNC(PyEval_ThreadsInitialized)
|
||||
EXPORT_FUNC(PyException_GetArgs)
|
||||
EXPORT_FUNC(PyException_GetCause)
|
||||
EXPORT_FUNC(PyException_GetContext)
|
||||
EXPORT_FUNC(PyException_GetTraceback)
|
||||
EXPORT_FUNC(PyException_SetArgs)
|
||||
EXPORT_FUNC(PyException_SetCause)
|
||||
EXPORT_FUNC(PyException_SetContext)
|
||||
EXPORT_FUNC(PyException_SetTraceback)
|
||||
|
|
|
@ -643,13 +643,10 @@ _PyPegen_number_token(Parser *p)
|
|||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
// The only way a ValueError should happen in _this_ code is via
|
||||
// PyLong_FromString hitting a length limit.
|
||||
if (tstate->curexc_type == PyExc_ValueError &&
|
||||
tstate->curexc_value != NULL) {
|
||||
PyObject *type, *value, *tb;
|
||||
// This acts as PyErr_Clear() as we're replacing curexc.
|
||||
PyErr_Fetch(&type, &value, &tb);
|
||||
Py_XDECREF(tb);
|
||||
Py_DECREF(type);
|
||||
if (tstate->current_exception != NULL &&
|
||||
Py_TYPE(tstate->current_exception) == (PyTypeObject *)PyExc_ValueError
|
||||
) {
|
||||
PyObject *exc = PyErr_GetRaisedException();
|
||||
/* Intentionally omitting columns to avoid a wall of 1000s of '^'s
|
||||
* on the error message. Nobody is going to overlook their huge
|
||||
* numeric literal once given the line. */
|
||||
|
@ -659,8 +656,8 @@ _PyPegen_number_token(Parser *p)
|
|||
t->end_lineno, -1 /* end_col_offset */,
|
||||
"%S - Consider hexadecimal for huge integer literals "
|
||||
"to avoid decimal conversion limits.",
|
||||
value);
|
||||
Py_DECREF(value);
|
||||
exc);
|
||||
Py_DECREF(exc);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -804,9 +804,7 @@ dummy_func(
|
|||
DECREF_INPUTS();
|
||||
}
|
||||
else {
|
||||
PyObject *exc_type = Py_NewRef(Py_TYPE(exc_value));
|
||||
PyObject *exc_traceback = PyException_GetTraceback(exc_value);
|
||||
_PyErr_Restore(tstate, exc_type, Py_NewRef(exc_value), exc_traceback);
|
||||
_PyErr_SetRaisedException(tstate, Py_NewRef(exc_value));
|
||||
goto exception_unwind;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2902,13 +2902,13 @@ format_kwargs_error(PyThreadState *tstate, PyObject *func, PyObject *kwargs)
|
|||
}
|
||||
}
|
||||
else if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
|
||||
PyObject *exc, *val, *tb;
|
||||
_PyErr_Fetch(tstate, &exc, &val, &tb);
|
||||
if (val && PyTuple_Check(val) && PyTuple_GET_SIZE(val) == 1) {
|
||||
PyObject *exc = _PyErr_GetRaisedException(tstate);
|
||||
PyObject *args = ((PyBaseExceptionObject *)exc)->args;
|
||||
if (exc && PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1) {
|
||||
_PyErr_Clear(tstate);
|
||||
PyObject *funcstr = _PyObject_FunctionStr(func);
|
||||
if (funcstr != NULL) {
|
||||
PyObject *key = PyTuple_GET_ITEM(val, 0);
|
||||
PyObject *key = PyTuple_GET_ITEM(args, 0);
|
||||
_PyErr_Format(
|
||||
tstate, PyExc_TypeError,
|
||||
"%U got multiple values for keyword argument '%S'",
|
||||
|
@ -2916,11 +2916,9 @@ format_kwargs_error(PyThreadState *tstate, PyObject *func, PyObject *kwargs)
|
|||
Py_DECREF(funcstr);
|
||||
}
|
||||
Py_XDECREF(exc);
|
||||
Py_XDECREF(val);
|
||||
Py_XDECREF(tb);
|
||||
}
|
||||
else {
|
||||
_PyErr_Restore(tstate, exc, val, tb);
|
||||
_PyErr_SetRaisedException(tstate, exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
203
Python/errors.c
203
Python/errors.c
|
@ -27,54 +27,12 @@ static PyObject *
|
|||
_PyErr_FormatV(PyThreadState *tstate, PyObject *exception,
|
||||
const char *format, va_list vargs);
|
||||
|
||||
|
||||
void
|
||||
_PyErr_Restore(PyThreadState *tstate, PyObject *type, PyObject *value,
|
||||
PyObject *traceback)
|
||||
_PyErr_SetRaisedException(PyThreadState *tstate, PyObject *exc)
|
||||
{
|
||||
PyObject *oldtype, *oldvalue, *oldtraceback;
|
||||
|
||||
if (traceback != NULL && !PyTraceBack_Check(traceback)) {
|
||||
/* XXX Should never happen -- fatal error instead? */
|
||||
/* Well, it could be None. */
|
||||
Py_SETREF(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);
|
||||
}
|
||||
|
||||
void
|
||||
PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback)
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
_PyErr_Restore(tstate, type, value, traceback);
|
||||
}
|
||||
|
||||
|
||||
_PyErr_StackItem *
|
||||
_PyErr_GetTopmostException(PyThreadState *tstate)
|
||||
{
|
||||
_PyErr_StackItem *exc_info = tstate->exc_info;
|
||||
assert(exc_info);
|
||||
|
||||
while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) &&
|
||||
exc_info->previous_item != NULL)
|
||||
{
|
||||
exc_info = exc_info->previous_item;
|
||||
}
|
||||
return exc_info;
|
||||
PyObject *old_exc = tstate->current_exception;
|
||||
tstate->current_exception = exc;
|
||||
Py_XDECREF(old_exc);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
|
@ -103,6 +61,80 @@ _PyErr_CreateException(PyObject *exception_type, PyObject *value)
|
|||
return exc;
|
||||
}
|
||||
|
||||
void
|
||||
_PyErr_Restore(PyThreadState *tstate, PyObject *type, PyObject *value,
|
||||
PyObject *traceback)
|
||||
{
|
||||
if (type == NULL) {
|
||||
assert(value == NULL);
|
||||
assert(traceback == NULL);
|
||||
_PyErr_SetRaisedException(tstate, NULL);
|
||||
return;
|
||||
}
|
||||
assert(PyExceptionClass_Check(type));
|
||||
if (value != NULL && type == (PyObject *)Py_TYPE(value)) {
|
||||
/* Already normalized */
|
||||
assert(((PyBaseExceptionObject *)value)->traceback != Py_None);
|
||||
}
|
||||
else {
|
||||
PyObject *exc = _PyErr_CreateException(type, value);
|
||||
Py_XDECREF(value);
|
||||
if (exc == NULL) {
|
||||
Py_DECREF(type);
|
||||
Py_XDECREF(traceback);
|
||||
return;
|
||||
}
|
||||
value = exc;
|
||||
}
|
||||
assert(PyExceptionInstance_Check(value));
|
||||
if (traceback != NULL && !PyTraceBack_Check(traceback)) {
|
||||
if (traceback == Py_None) {
|
||||
Py_DECREF(Py_None);
|
||||
traceback = NULL;
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "traceback must be a Traceback or None");
|
||||
Py_XDECREF(value);
|
||||
Py_DECREF(type);
|
||||
Py_XDECREF(traceback);
|
||||
return;
|
||||
}
|
||||
}
|
||||
PyObject *old_traceback = ((PyBaseExceptionObject *)value)->traceback;
|
||||
((PyBaseExceptionObject *)value)->traceback = traceback;
|
||||
Py_XDECREF(old_traceback);
|
||||
_PyErr_SetRaisedException(tstate, value);
|
||||
Py_DECREF(type);
|
||||
}
|
||||
|
||||
void
|
||||
PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback)
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
_PyErr_Restore(tstate, type, value, traceback);
|
||||
}
|
||||
|
||||
void
|
||||
PyErr_SetRaisedException(PyObject *exc)
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
_PyErr_SetRaisedException(tstate, exc);
|
||||
}
|
||||
|
||||
_PyErr_StackItem *
|
||||
_PyErr_GetTopmostException(PyThreadState *tstate)
|
||||
{
|
||||
_PyErr_StackItem *exc_info = tstate->exc_info;
|
||||
assert(exc_info);
|
||||
|
||||
while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) &&
|
||||
exc_info->previous_item != NULL)
|
||||
{
|
||||
exc_info = exc_info->previous_item;
|
||||
}
|
||||
return exc_info;
|
||||
}
|
||||
|
||||
void
|
||||
_PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value)
|
||||
{
|
||||
|
@ -117,13 +149,9 @@ _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value)
|
|||
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)) {
|
||||
/* Normalize the exception */
|
||||
if (value == NULL || (PyObject *)Py_TYPE(value) != exception) {
|
||||
/* We must normalize the value right now */
|
||||
PyObject *fixed_value;
|
||||
|
||||
|
@ -134,13 +162,16 @@ _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value)
|
|||
fixed_value = _PyErr_CreateException(exception, value);
|
||||
Py_XDECREF(value);
|
||||
if (fixed_value == NULL) {
|
||||
Py_DECREF(exc_value);
|
||||
return;
|
||||
}
|
||||
|
||||
value = fixed_value;
|
||||
}
|
||||
|
||||
exc_value = _PyErr_GetTopmostException(tstate)->exc_value;
|
||||
if (exc_value != NULL && exc_value != Py_None) {
|
||||
/* Implicit exception chaining */
|
||||
Py_INCREF(exc_value);
|
||||
/* Avoid creating new reference cycles through the
|
||||
context chain, while taking care not to hang on
|
||||
pre-existing ones.
|
||||
|
@ -414,17 +445,34 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
|
|||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
_PyErr_GetRaisedException(PyThreadState *tstate) {
|
||||
PyObject *exc = tstate->current_exception;
|
||||
tstate->current_exception = NULL;
|
||||
return exc;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyErr_GetRaisedException(void)
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
return _PyErr_GetRaisedException(tstate);
|
||||
}
|
||||
|
||||
void
|
||||
_PyErr_Fetch(PyThreadState *tstate, PyObject **p_type, PyObject **p_value,
|
||||
PyObject **p_traceback)
|
||||
{
|
||||
*p_type = tstate->curexc_type;
|
||||
*p_value = tstate->curexc_value;
|
||||
*p_traceback = tstate->curexc_traceback;
|
||||
|
||||
tstate->curexc_type = NULL;
|
||||
tstate->curexc_value = NULL;
|
||||
tstate->curexc_traceback = NULL;
|
||||
PyObject *exc = _PyErr_GetRaisedException(tstate);
|
||||
*p_value = exc;
|
||||
if (exc == NULL) {
|
||||
*p_type = NULL;
|
||||
*p_traceback = NULL;
|
||||
}
|
||||
else {
|
||||
*p_type = Py_NewRef(Py_TYPE(exc));
|
||||
*p_traceback = Py_XNewRef(((PyBaseExceptionObject *)exc)->traceback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -597,6 +645,28 @@ _PyErr_ChainExceptions(PyObject *typ, PyObject *val, PyObject *tb)
|
|||
}
|
||||
}
|
||||
|
||||
/* Like PyErr_SetRaisedException(), but if an exception is already set,
|
||||
set the context associated with it.
|
||||
|
||||
The caller is responsible for ensuring that this call won't create
|
||||
any cycles in the exception context chain. */
|
||||
void
|
||||
_PyErr_ChainExceptions1(PyObject *exc)
|
||||
{
|
||||
if (exc == NULL) {
|
||||
return;
|
||||
}
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
if (_PyErr_Occurred(tstate)) {
|
||||
PyObject *exc2 = _PyErr_GetRaisedException(tstate);
|
||||
PyException_SetContext(exc2, exc);
|
||||
_PyErr_SetRaisedException(tstate, exc2);
|
||||
}
|
||||
else {
|
||||
_PyErr_SetRaisedException(tstate, exc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the currently set exception's context to the given exception.
|
||||
|
||||
If the provided exc_info is NULL, then the current Python thread state's
|
||||
|
@ -706,19 +776,6 @@ PyErr_BadArgument(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyErr_NoMemory(PyThreadState *tstate)
|
||||
{
|
||||
if (Py_IS_TYPE(PyExc_MemoryError, NULL)) {
|
||||
/* PyErr_NoMemory() has been called before PyExc_MemoryError has been
|
||||
initialized by _PyExc_Init() */
|
||||
Py_FatalError("Out of memory and PyExc_MemoryError is not "
|
||||
"initialized yet");
|
||||
}
|
||||
_PyErr_SetNone(tstate, PyExc_MemoryError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyErr_NoMemory(void)
|
||||
{
|
||||
|
|
|
@ -1036,9 +1036,7 @@
|
|||
Py_DECREF(exc_value);
|
||||
}
|
||||
else {
|
||||
PyObject *exc_type = Py_NewRef(Py_TYPE(exc_value));
|
||||
PyObject *exc_traceback = PyException_GetTraceback(exc_value);
|
||||
_PyErr_Restore(tstate, exc_type, Py_NewRef(exc_value), exc_traceback);
|
||||
_PyErr_SetRaisedException(tstate, Py_NewRef(exc_value));
|
||||
goto exception_unwind;
|
||||
}
|
||||
STACK_SHRINK(2);
|
||||
|
|
|
@ -1592,6 +1592,13 @@ remove_importlib_frames(PyThreadState *tstate)
|
|||
Py_DECREF(code);
|
||||
tb = next;
|
||||
}
|
||||
assert(PyExceptionInstance_Check(value));
|
||||
assert((PyObject *)Py_TYPE(value) == exception);
|
||||
if (base_tb == NULL) {
|
||||
base_tb = Py_None;
|
||||
Py_INCREF(Py_None);
|
||||
}
|
||||
PyException_SetTraceback(value, base_tb);
|
||||
done:
|
||||
_PyErr_Restore(tstate, exception, value, base_tb);
|
||||
}
|
||||
|
|
|
@ -3143,8 +3143,7 @@ init_dump_ascii_wstr(const wchar_t *str)
|
|||
void
|
||||
_Py_DumpPathConfig(PyThreadState *tstate)
|
||||
{
|
||||
PyObject *exc_type, *exc_value, *exc_tb;
|
||||
_PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb);
|
||||
PyObject *exc = _PyErr_GetRaisedException(tstate);
|
||||
|
||||
PySys_WriteStderr("Python path configuration:\n");
|
||||
|
||||
|
@ -3202,5 +3201,5 @@ _Py_DumpPathConfig(PyThreadState *tstate)
|
|||
PySys_WriteStderr(" ]\n");
|
||||
}
|
||||
|
||||
_PyErr_Restore(tstate, exc_type, exc_value, exc_tb);
|
||||
_PyErr_SetRaisedException(tstate, exc);
|
||||
}
|
||||
|
|
|
@ -1375,9 +1375,7 @@ PyThreadState_Clear(PyThreadState *tstate)
|
|||
Py_CLEAR(tstate->dict);
|
||||
Py_CLEAR(tstate->async_exc);
|
||||
|
||||
Py_CLEAR(tstate->curexc_type);
|
||||
Py_CLEAR(tstate->curexc_value);
|
||||
Py_CLEAR(tstate->curexc_traceback);
|
||||
Py_CLEAR(tstate->current_exception);
|
||||
|
||||
Py_CLEAR(tstate->exc_state.exc_value);
|
||||
|
||||
|
|
|
@ -748,13 +748,10 @@ _Py_HandleSystemExit(int *exitcode_p)
|
|||
}
|
||||
|
||||
done:
|
||||
/* Restore and clear the exception info, in order to properly decref
|
||||
* the exception, value, and traceback. If we just exit instead,
|
||||
* these leak, which confuses PYTHONDUMPREFS output, and may prevent
|
||||
* some finalizers from running.
|
||||
*/
|
||||
PyErr_Restore(exception, value, tb);
|
||||
PyErr_Clear();
|
||||
/* Cleanup the exception */
|
||||
Py_CLEAR(exception);
|
||||
Py_CLEAR(value);
|
||||
Py_CLEAR(tb);
|
||||
*exitcode_p = exitcode;
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -66,12 +66,11 @@ _PySys_GetAttr(PyThreadState *tstate, PyObject *name)
|
|||
if (sd == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *exc_type, *exc_value, *exc_tb;
|
||||
_PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb);
|
||||
PyObject *exc = _PyErr_GetRaisedException(tstate);
|
||||
/* XXX Suppress a new exception if it was raised and restore
|
||||
* the old one. */
|
||||
PyObject *value = _PyDict_GetItemWithError(sd, name);
|
||||
_PyErr_Restore(tstate, exc_type, exc_value, exc_tb);
|
||||
_PyErr_SetRaisedException(tstate, exc);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -3704,11 +3703,10 @@ static void
|
|||
sys_format(PyObject *key, FILE *fp, const char *format, va_list va)
|
||||
{
|
||||
PyObject *file, *message;
|
||||
PyObject *error_type, *error_value, *error_traceback;
|
||||
const char *utf8;
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
|
||||
_PyErr_Fetch(tstate, &error_type, &error_value, &error_traceback);
|
||||
PyObject *error = _PyErr_GetRaisedException(tstate);
|
||||
file = _PySys_GetAttr(tstate, key);
|
||||
message = PyUnicode_FromFormatV(format, va);
|
||||
if (message != NULL) {
|
||||
|
@ -3720,7 +3718,7 @@ sys_format(PyObject *key, FILE *fp, const char *format, va_list va)
|
|||
}
|
||||
Py_DECREF(message);
|
||||
}
|
||||
_PyErr_Restore(tstate, error_type, error_value, error_traceback);
|
||||
_PyErr_SetRaisedException(tstate, error);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -249,6 +249,8 @@ PyTraceBack_Here(PyFrameObject *frame)
|
|||
_PyErr_ChainExceptions(exc, val, tb);
|
||||
return -1;
|
||||
}
|
||||
assert(PyExceptionInstance_Check(val));
|
||||
PyException_SetTraceback(val, newtb);
|
||||
PyErr_Restore(exc, val, newtb);
|
||||
Py_XDECREF(tb);
|
||||
return 0;
|
||||
|
@ -260,13 +262,12 @@ void _PyTraceback_Add(const char *funcname, const char *filename, int lineno)
|
|||
PyObject *globals;
|
||||
PyCodeObject *code;
|
||||
PyFrameObject *frame;
|
||||
PyObject *exc, *val, *tb;
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
|
||||
/* Save and clear the current exception. Python functions must not be
|
||||
called with an exception set. Calling Python functions happens when
|
||||
the codec of the filesystem encoding is implemented in pure Python. */
|
||||
_PyErr_Fetch(tstate, &exc, &val, &tb);
|
||||
PyObject *exc = _PyErr_GetRaisedException(tstate);
|
||||
|
||||
globals = PyDict_New();
|
||||
if (!globals)
|
||||
|
@ -283,13 +284,13 @@ void _PyTraceback_Add(const char *funcname, const char *filename, int lineno)
|
|||
goto error;
|
||||
frame->f_lineno = lineno;
|
||||
|
||||
_PyErr_Restore(tstate, exc, val, tb);
|
||||
_PyErr_SetRaisedException(tstate, exc);
|
||||
PyTraceBack_Here(frame);
|
||||
Py_DECREF(frame);
|
||||
return;
|
||||
|
||||
error:
|
||||
_PyErr_ChainExceptions(exc, val, tb);
|
||||
_PyErr_ChainExceptions1(exc);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
|
Loading…
Reference in New Issue