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.
|
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)
|
.. 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.
|
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
|
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
|
set, it will be cleared and you own a reference to each object retrieved. The
|
||||||
|
@ -421,10 +474,14 @@ Querying the error indicator
|
||||||
PyErr_Restore(type, value, traceback);
|
PyErr_Restore(type, value, traceback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.. deprecated:: 3.12
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: void PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback)
|
.. c:function:: void PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback)
|
||||||
|
|
||||||
Set the error indicator from the three objects. If the error indicator is
|
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
|
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
|
indicator is cleared. Do not pass a ``NULL`` type and non-``NULL`` value or
|
||||||
traceback. The exception type should be a class. Do not pass an invalid
|
traceback. The exception type should be a class. Do not pass an invalid
|
||||||
|
@ -440,9 +497,15 @@ Querying the error indicator
|
||||||
error indicator temporarily. Use :c:func:`PyErr_Fetch` to save the current
|
error indicator temporarily. Use :c:func:`PyErr_Fetch` to save the current
|
||||||
error indicator.
|
error indicator.
|
||||||
|
|
||||||
|
.. deprecated:: 3.12
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: void PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
|
.. 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
|
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
|
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
|
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);
|
PyException_SetTraceback(val, tb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.. deprecated:: 3.12
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: PyObject* PyErr_GetHandledException(void)
|
.. c:function:: PyObject* PyErr_GetHandledException(void)
|
||||||
|
|
||||||
|
@ -704,6 +769,18 @@ Exception Objects
|
||||||
:attr:`__suppress_context__` is implicitly set to ``True`` by this function.
|
: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:
|
.. _unicodeexceptions:
|
||||||
|
|
||||||
Unicode Exception Objects
|
Unicode Exception Objects
|
||||||
|
|
|
@ -139,6 +139,7 @@ function,PyErr_Format,3.2,,
|
||||||
function,PyErr_FormatV,3.5,,
|
function,PyErr_FormatV,3.5,,
|
||||||
function,PyErr_GetExcInfo,3.7,,
|
function,PyErr_GetExcInfo,3.7,,
|
||||||
function,PyErr_GetHandledException,3.11,,
|
function,PyErr_GetHandledException,3.11,,
|
||||||
|
function,PyErr_GetRaisedException,3.12,,
|
||||||
function,PyErr_GivenExceptionMatches,3.2,,
|
function,PyErr_GivenExceptionMatches,3.2,,
|
||||||
function,PyErr_NewException,3.2,,
|
function,PyErr_NewException,3.2,,
|
||||||
function,PyErr_NewExceptionWithDoc,3.2,,
|
function,PyErr_NewExceptionWithDoc,3.2,,
|
||||||
|
@ -168,6 +169,7 @@ function,PyErr_SetInterrupt,3.2,,
|
||||||
function,PyErr_SetInterruptEx,3.10,,
|
function,PyErr_SetInterruptEx,3.10,,
|
||||||
function,PyErr_SetNone,3.2,,
|
function,PyErr_SetNone,3.2,,
|
||||||
function,PyErr_SetObject,3.2,,
|
function,PyErr_SetObject,3.2,,
|
||||||
|
function,PyErr_SetRaisedException,3.12,,
|
||||||
function,PyErr_SetString,3.2,,
|
function,PyErr_SetString,3.2,,
|
||||||
function,PyErr_SyntaxLocation,3.2,,
|
function,PyErr_SyntaxLocation,3.2,,
|
||||||
function,PyErr_SyntaxLocationEx,3.7,,
|
function,PyErr_SyntaxLocationEx,3.7,,
|
||||||
|
@ -266,9 +268,11 @@ var,PyExc_Warning,3.2,,
|
||||||
var,PyExc_WindowsError,3.7,on Windows,
|
var,PyExc_WindowsError,3.7,on Windows,
|
||||||
var,PyExc_ZeroDivisionError,3.2,,
|
var,PyExc_ZeroDivisionError,3.2,,
|
||||||
function,PyExceptionClass_Name,3.8,,
|
function,PyExceptionClass_Name,3.8,,
|
||||||
|
function,PyException_GetArgs,3.12,,
|
||||||
function,PyException_GetCause,3.2,,
|
function,PyException_GetCause,3.2,,
|
||||||
function,PyException_GetContext,3.2,,
|
function,PyException_GetContext,3.2,,
|
||||||
function,PyException_GetTraceback,3.2,,
|
function,PyException_GetTraceback,3.2,,
|
||||||
|
function,PyException_SetArgs,3.12,,
|
||||||
function,PyException_SetCause,3.2,,
|
function,PyException_SetCause,3.2,,
|
||||||
function,PyException_SetContext,3.2,,
|
function,PyException_SetContext,3.2,,
|
||||||
function,PyException_SetTraceback,3.2,,
|
function,PyException_SetTraceback,3.2,,
|
||||||
|
|
|
@ -99,6 +99,7 @@ PyAPI_FUNC(void) _PyErr_GetExcInfo(PyThreadState *, PyObject **, PyObject **, Py
|
||||||
/* Context manipulation (PEP 3134) */
|
/* Context manipulation (PEP 3134) */
|
||||||
|
|
||||||
PyAPI_FUNC(void) _PyErr_ChainExceptions(PyObject *, PyObject *, PyObject *);
|
PyAPI_FUNC(void) _PyErr_ChainExceptions(PyObject *, PyObject *, PyObject *);
|
||||||
|
PyAPI_FUNC(void) _PyErr_ChainExceptions1(PyObject *);
|
||||||
|
|
||||||
/* Like PyErr_Format(), but saves current exception as __context__ and
|
/* Like PyErr_Format(), but saves current exception as __context__ and
|
||||||
__cause__.
|
__cause__.
|
||||||
|
|
|
@ -166,9 +166,7 @@ struct _ts {
|
||||||
PyObject *c_traceobj;
|
PyObject *c_traceobj;
|
||||||
|
|
||||||
/* The exception currently being raised */
|
/* The exception currently being raised */
|
||||||
PyObject *curexc_type;
|
PyObject *current_exception;
|
||||||
PyObject *curexc_value;
|
|
||||||
PyObject *curexc_traceback;
|
|
||||||
|
|
||||||
/* Pointer to the top of the exception stack for the exceptions
|
/* Pointer to the top of the exception stack for the exceptions
|
||||||
* we may be currently handling. (See _PyErr_StackItem above.)
|
* 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)
|
static inline PyObject* _PyErr_Occurred(PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
assert(tstate != NULL);
|
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)
|
static inline void _PyErr_ClearExcState(_PyErr_StackItem *exc_state)
|
||||||
|
@ -37,10 +40,16 @@ PyAPI_FUNC(void) _PyErr_Fetch(
|
||||||
PyObject **value,
|
PyObject **value,
|
||||||
PyObject **traceback);
|
PyObject **traceback);
|
||||||
|
|
||||||
|
extern PyObject *
|
||||||
|
_PyErr_GetRaisedException(PyThreadState *tstate);
|
||||||
|
|
||||||
PyAPI_FUNC(int) _PyErr_ExceptionMatches(
|
PyAPI_FUNC(int) _PyErr_ExceptionMatches(
|
||||||
PyThreadState *tstate,
|
PyThreadState *tstate,
|
||||||
PyObject *exc);
|
PyObject *exc);
|
||||||
|
|
||||||
|
void
|
||||||
|
_PyErr_SetRaisedException(PyThreadState *tstate, PyObject *exc);
|
||||||
|
|
||||||
PyAPI_FUNC(void) _PyErr_Restore(
|
PyAPI_FUNC(void) _PyErr_Restore(
|
||||||
PyThreadState *tstate,
|
PyThreadState *tstate,
|
||||||
PyObject *type,
|
PyObject *type,
|
||||||
|
|
|
@ -18,6 +18,8 @@ PyAPI_FUNC(PyObject *) PyErr_Occurred(void);
|
||||||
PyAPI_FUNC(void) PyErr_Clear(void);
|
PyAPI_FUNC(void) PyErr_Clear(void);
|
||||||
PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **);
|
PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **);
|
||||||
PyAPI_FUNC(void) PyErr_Restore(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
|
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030b0000
|
||||||
PyAPI_FUNC(PyObject*) PyErr_GetHandledException(void);
|
PyAPI_FUNC(PyObject*) PyErr_GetHandledException(void);
|
||||||
PyAPI_FUNC(void) PyErr_SetHandledException(PyObject *);
|
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(PyObject *) PyException_GetContext(PyObject *);
|
||||||
PyAPI_FUNC(void) PyException_SetContext(PyObject *, 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) \
|
#define PyExceptionClass_Check(x) \
|
||||||
|
|
|
@ -1553,5 +1553,44 @@ class Test_Pep523API(unittest.TestCase):
|
||||||
self.do_test(func2)
|
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__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -347,6 +347,7 @@ class ExceptionTests(unittest.TestCase):
|
||||||
_testcapi.raise_exception(BadException, 0)
|
_testcapi.raise_exception(BadException, 0)
|
||||||
except RuntimeError as err:
|
except RuntimeError as err:
|
||||||
exc, err, tb = sys.exc_info()
|
exc, err, tb = sys.exc_info()
|
||||||
|
tb = tb.tb_next
|
||||||
co = tb.tb_frame.f_code
|
co = tb.tb_frame.f_code
|
||||||
self.assertEqual(co.co_name, "__init__")
|
self.assertEqual(co.co_name, "__init__")
|
||||||
self.assertTrue(co.co_filename.endswith('test_exceptions.py'))
|
self.assertTrue(co.co_filename.endswith('test_exceptions.py'))
|
||||||
|
@ -1415,8 +1416,8 @@ class ExceptionTests(unittest.TestCase):
|
||||||
@cpython_only
|
@cpython_only
|
||||||
def test_recursion_normalizing_infinite_exception(self):
|
def test_recursion_normalizing_infinite_exception(self):
|
||||||
# Issue #30697. Test that a RecursionError is raised when
|
# Issue #30697. Test that a RecursionError is raised when
|
||||||
# PyErr_NormalizeException() maximum recursion depth has been
|
# maximum recursion depth has been exceeded when creating
|
||||||
# exceeded.
|
# an exception
|
||||||
code = """if 1:
|
code = """if 1:
|
||||||
import _testcapi
|
import _testcapi
|
||||||
try:
|
try:
|
||||||
|
@ -1426,8 +1427,7 @@ class ExceptionTests(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
rc, out, err = script_helper.assert_python_failure("-c", code)
|
rc, out, err = script_helper.assert_python_failure("-c", code)
|
||||||
self.assertEqual(rc, 1)
|
self.assertEqual(rc, 1)
|
||||||
self.assertIn(b'RecursionError: maximum recursion depth exceeded '
|
self.assertIn(b'RecursionError: maximum recursion depth exceeded', err)
|
||||||
b'while normalizing an exception', err)
|
|
||||||
self.assertIn(b'Done.', out)
|
self.assertIn(b'Done.', out)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -172,6 +172,7 @@ SYMBOL_NAMES = (
|
||||||
"PyErr_FormatV",
|
"PyErr_FormatV",
|
||||||
"PyErr_GetExcInfo",
|
"PyErr_GetExcInfo",
|
||||||
"PyErr_GetHandledException",
|
"PyErr_GetHandledException",
|
||||||
|
"PyErr_GetRaisedException",
|
||||||
"PyErr_GivenExceptionMatches",
|
"PyErr_GivenExceptionMatches",
|
||||||
"PyErr_NewException",
|
"PyErr_NewException",
|
||||||
"PyErr_NewExceptionWithDoc",
|
"PyErr_NewExceptionWithDoc",
|
||||||
|
@ -195,6 +196,7 @@ SYMBOL_NAMES = (
|
||||||
"PyErr_SetInterruptEx",
|
"PyErr_SetInterruptEx",
|
||||||
"PyErr_SetNone",
|
"PyErr_SetNone",
|
||||||
"PyErr_SetObject",
|
"PyErr_SetObject",
|
||||||
|
"PyErr_SetRaisedException",
|
||||||
"PyErr_SetString",
|
"PyErr_SetString",
|
||||||
"PyErr_SyntaxLocation",
|
"PyErr_SyntaxLocation",
|
||||||
"PyErr_SyntaxLocationEx",
|
"PyErr_SyntaxLocationEx",
|
||||||
|
@ -292,9 +294,11 @@ SYMBOL_NAMES = (
|
||||||
"PyExc_Warning",
|
"PyExc_Warning",
|
||||||
"PyExc_ZeroDivisionError",
|
"PyExc_ZeroDivisionError",
|
||||||
"PyExceptionClass_Name",
|
"PyExceptionClass_Name",
|
||||||
|
"PyException_GetArgs",
|
||||||
"PyException_GetCause",
|
"PyException_GetCause",
|
||||||
"PyException_GetContext",
|
"PyException_GetContext",
|
||||||
"PyException_GetTraceback",
|
"PyException_GetTraceback",
|
||||||
|
"PyException_SetArgs",
|
||||||
"PyException_SetCause",
|
"PyException_SetCause",
|
||||||
"PyException_SetContext",
|
"PyException_SetContext",
|
||||||
"PyException_SetTraceback",
|
"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'
|
added = '3.12'
|
||||||
[function.PyVectorcall_Call]
|
[function.PyVectorcall_Call]
|
||||||
added = '3.12'
|
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]
|
[typedef.vectorcallfunc]
|
||||||
added = '3.12'
|
added = '3.12'
|
||||||
[function.PyObject_Vectorcall]
|
[function.PyObject_Vectorcall]
|
||||||
|
|
|
@ -116,10 +116,10 @@ test_from_spec_invalid_metatype_inheritance(PyObject *self, PyObject *Py_UNUSED(
|
||||||
PyObject *bases = NULL;
|
PyObject *bases = NULL;
|
||||||
PyObject *new = NULL;
|
PyObject *new = NULL;
|
||||||
PyObject *meta_error_string = NULL;
|
PyObject *meta_error_string = NULL;
|
||||||
PyObject *exc_type = NULL;
|
PyObject *exc = NULL;
|
||||||
PyObject *exc_value = NULL;
|
|
||||||
PyObject *exc_traceback = NULL;
|
|
||||||
PyObject *result = NULL;
|
PyObject *result = NULL;
|
||||||
|
PyObject *message = NULL;
|
||||||
|
PyObject *args = NULL;
|
||||||
|
|
||||||
metaclass_a = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
|
metaclass_a = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
|
||||||
if (metaclass_a == NULL) {
|
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
|
// Assert that the correct exception was raised
|
||||||
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
|
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:");
|
meta_error_string = PyUnicode_FromString("metaclass conflict:");
|
||||||
if (meta_error_string == NULL) {
|
if (meta_error_string == NULL) {
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
int res = PyUnicode_Contains(exc_value, meta_error_string);
|
int res = PyUnicode_Contains(message, meta_error_string);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
|
@ -179,11 +185,11 @@ finally:
|
||||||
Py_XDECREF(bases);
|
Py_XDECREF(bases);
|
||||||
Py_XDECREF(new);
|
Py_XDECREF(new);
|
||||||
Py_XDECREF(meta_error_string);
|
Py_XDECREF(meta_error_string);
|
||||||
Py_XDECREF(exc_type);
|
Py_XDECREF(exc);
|
||||||
Py_XDECREF(exc_value);
|
Py_XDECREF(message);
|
||||||
Py_XDECREF(exc_traceback);
|
|
||||||
Py_XDECREF(class_a);
|
Py_XDECREF(class_a);
|
||||||
Py_XDECREF(class_b);
|
Py_XDECREF(class_b);
|
||||||
|
Py_XDECREF(args);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3470,6 +3470,41 @@ function_set_kw_defaults(PyObject *self, PyObject *args)
|
||||||
Py_RETURN_NONE;
|
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 PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);
|
||||||
|
|
||||||
static PyMethodDef TestMethods[] = {
|
static PyMethodDef TestMethods[] = {
|
||||||
|
@ -3622,6 +3657,8 @@ static PyMethodDef TestMethods[] = {
|
||||||
{"function_set_defaults", function_set_defaults, METH_VARARGS, NULL},
|
{"function_set_defaults", function_set_defaults, METH_VARARGS, NULL},
|
||||||
{"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL},
|
{"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL},
|
||||||
{"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, 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 */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2082,11 +2082,10 @@ PyGC_Collect(void)
|
||||||
n = 0;
|
n = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyObject *exc, *value, *tb;
|
|
||||||
gcstate->collecting = 1;
|
gcstate->collecting = 1;
|
||||||
_PyErr_Fetch(tstate, &exc, &value, &tb);
|
PyObject *exc = _PyErr_GetRaisedException(tstate);
|
||||||
n = gc_collect_with_callback(tstate, NUM_GENERATIONS - 1);
|
n = gc_collect_with_callback(tstate, NUM_GENERATIONS - 1);
|
||||||
_PyErr_Restore(tstate, exc, value, tb);
|
_PyErr_SetRaisedException(tstate, exc);
|
||||||
gcstate->collecting = 0;
|
gcstate->collecting = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1663,15 +1663,15 @@ PyDict_GetItem(PyObject *op, PyObject *key)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Preserve the existing exception */
|
/* Preserve the existing exception */
|
||||||
PyObject *exc_type, *exc_value, *exc_tb;
|
|
||||||
PyObject *value;
|
PyObject *value;
|
||||||
Py_ssize_t ix; (void)ix;
|
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);
|
ix = _Py_dict_lookup(mp, key, hash, &value);
|
||||||
|
|
||||||
/* Ignore any exception raised by the lookup */
|
/* 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);
|
assert(ix >= 0 || value == NULL);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "pycore_ceval.h" // _Py_EnterRecursiveCall
|
#include "pycore_ceval.h" // _Py_EnterRecursiveCall
|
||||||
|
#include "pycore_pyerrors.h" // struct _PyErr_SetRaisedException
|
||||||
#include "pycore_exceptions.h" // struct _Py_exc_state
|
#include "pycore_exceptions.h" // struct _Py_exc_state
|
||||||
#include "pycore_initconfig.h"
|
#include "pycore_initconfig.h"
|
||||||
#include "pycore_object.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");
|
PyErr_SetString(PyExc_TypeError, "__traceback__ may not be deleted");
|
||||||
return -1;
|
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,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"__traceback__ must be a traceback or None");
|
"__traceback__ must be a traceback or None");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_XSETREF(self->traceback, Py_NewRef(tb));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,6 +418,20 @@ PyException_SetContext(PyObject *self, PyObject *context)
|
||||||
Py_XSETREF(_PyBaseExceptionObject_cast(self)->context, 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 *
|
const char *
|
||||||
PyExceptionClass_Name(PyObject *ob)
|
PyExceptionClass_Name(PyObject *ob)
|
||||||
{
|
{
|
||||||
|
@ -3188,20 +3207,19 @@ SimpleExtendsException(PyExc_Exception, ReferenceError,
|
||||||
|
|
||||||
#define MEMERRORS_SAVE 16
|
#define MEMERRORS_SAVE 16
|
||||||
|
|
||||||
|
static PyBaseExceptionObject last_resort_memory_error;
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
get_memory_error(int allow_allocation, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
PyBaseExceptionObject *self;
|
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();
|
struct _Py_exc_state *state = get_exc_state();
|
||||||
if (state->memerrors_freelist == NULL) {
|
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 */
|
/* Fetch object from freelist and revive it */
|
||||||
|
@ -3221,6 +3239,35 @@ MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
return (PyObject *)self;
|
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
|
static void
|
||||||
MemoryError_dealloc(PyBaseExceptionObject *self)
|
MemoryError_dealloc(PyBaseExceptionObject *self)
|
||||||
{
|
{
|
||||||
|
@ -3252,6 +3299,7 @@ preallocate_memerrors(void)
|
||||||
/* We create enough MemoryErrors and then decref them, which will fill
|
/* We create enough MemoryErrors and then decref them, which will fill
|
||||||
up the freelist. */
|
up the freelist. */
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
PyObject *errors[MEMERRORS_SAVE];
|
PyObject *errors[MEMERRORS_SAVE];
|
||||||
for (i = 0; i < MEMERRORS_SAVE; i++) {
|
for (i = 0; i < MEMERRORS_SAVE; i++) {
|
||||||
errors[i] = MemoryError_new((PyTypeObject *) PyExc_MemoryError,
|
errors[i] = MemoryError_new((PyTypeObject *) PyExc_MemoryError,
|
||||||
|
@ -3291,6 +3339,9 @@ static PyTypeObject _PyExc_MemoryError = {
|
||||||
};
|
};
|
||||||
PyObject *PyExc_MemoryError = (PyObject *) &_PyExc_MemoryError;
|
PyObject *PyExc_MemoryError = (PyObject *) &_PyExc_MemoryError;
|
||||||
|
|
||||||
|
static PyBaseExceptionObject last_resort_memory_error = {
|
||||||
|
_PyObject_IMMORTAL_INIT(&_PyExc_MemoryError)
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BufferError extends Exception
|
* BufferError extends Exception
|
||||||
|
|
|
@ -2416,10 +2416,10 @@ _Py_Dealloc(PyObject *op)
|
||||||
destructor dealloc = type->tp_dealloc;
|
destructor dealloc = type->tp_dealloc;
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
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
|
// Keep the old exception type alive to prevent undefined behavior
|
||||||
// on (tstate->curexc_type != old_exc_type) below
|
// 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
|
// Make sure that type->tp_name remains valid
|
||||||
Py_INCREF(type);
|
Py_INCREF(type);
|
||||||
#endif
|
#endif
|
||||||
|
@ -2432,12 +2432,12 @@ _Py_Dealloc(PyObject *op)
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
// gh-89373: The tp_dealloc function must leave the current exception
|
// gh-89373: The tp_dealloc function must leave the current exception
|
||||||
// unchanged.
|
// unchanged.
|
||||||
if (tstate != NULL && tstate->curexc_type != old_exc_type) {
|
if (tstate != NULL && tstate->current_exception != old_exc) {
|
||||||
const char *err;
|
const char *err;
|
||||||
if (old_exc_type == NULL) {
|
if (old_exc == NULL) {
|
||||||
err = "Deallocator of type '%s' raised an exception";
|
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";
|
err = "Deallocator of type '%s' cleared the current exception";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -2448,7 +2448,7 @@ _Py_Dealloc(PyObject *op)
|
||||||
}
|
}
|
||||||
_Py_FatalErrorFormat(__func__, err, type->tp_name);
|
_Py_FatalErrorFormat(__func__, err, type->tp_name);
|
||||||
}
|
}
|
||||||
Py_XDECREF(old_exc_type);
|
Py_XDECREF(old_exc);
|
||||||
Py_DECREF(type);
|
Py_DECREF(type);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,6 +198,7 @@ EXPORT_FUNC(PyErr_Format)
|
||||||
EXPORT_FUNC(PyErr_FormatV)
|
EXPORT_FUNC(PyErr_FormatV)
|
||||||
EXPORT_FUNC(PyErr_GetExcInfo)
|
EXPORT_FUNC(PyErr_GetExcInfo)
|
||||||
EXPORT_FUNC(PyErr_GetHandledException)
|
EXPORT_FUNC(PyErr_GetHandledException)
|
||||||
|
EXPORT_FUNC(PyErr_GetRaisedException)
|
||||||
EXPORT_FUNC(PyErr_GivenExceptionMatches)
|
EXPORT_FUNC(PyErr_GivenExceptionMatches)
|
||||||
EXPORT_FUNC(PyErr_NewException)
|
EXPORT_FUNC(PyErr_NewException)
|
||||||
EXPORT_FUNC(PyErr_NewExceptionWithDoc)
|
EXPORT_FUNC(PyErr_NewExceptionWithDoc)
|
||||||
|
@ -227,6 +228,7 @@ EXPORT_FUNC(PyErr_SetInterrupt)
|
||||||
EXPORT_FUNC(PyErr_SetInterruptEx)
|
EXPORT_FUNC(PyErr_SetInterruptEx)
|
||||||
EXPORT_FUNC(PyErr_SetNone)
|
EXPORT_FUNC(PyErr_SetNone)
|
||||||
EXPORT_FUNC(PyErr_SetObject)
|
EXPORT_FUNC(PyErr_SetObject)
|
||||||
|
EXPORT_FUNC(PyErr_SetRaisedException)
|
||||||
EXPORT_FUNC(PyErr_SetString)
|
EXPORT_FUNC(PyErr_SetString)
|
||||||
EXPORT_FUNC(PyErr_SyntaxLocation)
|
EXPORT_FUNC(PyErr_SyntaxLocation)
|
||||||
EXPORT_FUNC(PyErr_SyntaxLocationEx)
|
EXPORT_FUNC(PyErr_SyntaxLocationEx)
|
||||||
|
@ -255,9 +257,11 @@ EXPORT_FUNC(PyEval_ReleaseThread)
|
||||||
EXPORT_FUNC(PyEval_RestoreThread)
|
EXPORT_FUNC(PyEval_RestoreThread)
|
||||||
EXPORT_FUNC(PyEval_SaveThread)
|
EXPORT_FUNC(PyEval_SaveThread)
|
||||||
EXPORT_FUNC(PyEval_ThreadsInitialized)
|
EXPORT_FUNC(PyEval_ThreadsInitialized)
|
||||||
|
EXPORT_FUNC(PyException_GetArgs)
|
||||||
EXPORT_FUNC(PyException_GetCause)
|
EXPORT_FUNC(PyException_GetCause)
|
||||||
EXPORT_FUNC(PyException_GetContext)
|
EXPORT_FUNC(PyException_GetContext)
|
||||||
EXPORT_FUNC(PyException_GetTraceback)
|
EXPORT_FUNC(PyException_GetTraceback)
|
||||||
|
EXPORT_FUNC(PyException_SetArgs)
|
||||||
EXPORT_FUNC(PyException_SetCause)
|
EXPORT_FUNC(PyException_SetCause)
|
||||||
EXPORT_FUNC(PyException_SetContext)
|
EXPORT_FUNC(PyException_SetContext)
|
||||||
EXPORT_FUNC(PyException_SetTraceback)
|
EXPORT_FUNC(PyException_SetTraceback)
|
||||||
|
|
|
@ -643,13 +643,10 @@ _PyPegen_number_token(Parser *p)
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
// The only way a ValueError should happen in _this_ code is via
|
// The only way a ValueError should happen in _this_ code is via
|
||||||
// PyLong_FromString hitting a length limit.
|
// PyLong_FromString hitting a length limit.
|
||||||
if (tstate->curexc_type == PyExc_ValueError &&
|
if (tstate->current_exception != NULL &&
|
||||||
tstate->curexc_value != NULL) {
|
Py_TYPE(tstate->current_exception) == (PyTypeObject *)PyExc_ValueError
|
||||||
PyObject *type, *value, *tb;
|
) {
|
||||||
// This acts as PyErr_Clear() as we're replacing curexc.
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
PyErr_Fetch(&type, &value, &tb);
|
|
||||||
Py_XDECREF(tb);
|
|
||||||
Py_DECREF(type);
|
|
||||||
/* Intentionally omitting columns to avoid a wall of 1000s of '^'s
|
/* Intentionally omitting columns to avoid a wall of 1000s of '^'s
|
||||||
* on the error message. Nobody is going to overlook their huge
|
* on the error message. Nobody is going to overlook their huge
|
||||||
* numeric literal once given the line. */
|
* numeric literal once given the line. */
|
||||||
|
@ -659,8 +656,8 @@ _PyPegen_number_token(Parser *p)
|
||||||
t->end_lineno, -1 /* end_col_offset */,
|
t->end_lineno, -1 /* end_col_offset */,
|
||||||
"%S - Consider hexadecimal for huge integer literals "
|
"%S - Consider hexadecimal for huge integer literals "
|
||||||
"to avoid decimal conversion limits.",
|
"to avoid decimal conversion limits.",
|
||||||
value);
|
exc);
|
||||||
Py_DECREF(value);
|
Py_DECREF(exc);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -804,9 +804,7 @@ dummy_func(
|
||||||
DECREF_INPUTS();
|
DECREF_INPUTS();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyObject *exc_type = Py_NewRef(Py_TYPE(exc_value));
|
_PyErr_SetRaisedException(tstate, Py_NewRef(exc_value));
|
||||||
PyObject *exc_traceback = PyException_GetTraceback(exc_value);
|
|
||||||
_PyErr_Restore(tstate, exc_type, Py_NewRef(exc_value), exc_traceback);
|
|
||||||
goto exception_unwind;
|
goto exception_unwind;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2902,13 +2902,13 @@ format_kwargs_error(PyThreadState *tstate, PyObject *func, PyObject *kwargs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
|
else if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
|
||||||
PyObject *exc, *val, *tb;
|
PyObject *exc = _PyErr_GetRaisedException(tstate);
|
||||||
_PyErr_Fetch(tstate, &exc, &val, &tb);
|
PyObject *args = ((PyBaseExceptionObject *)exc)->args;
|
||||||
if (val && PyTuple_Check(val) && PyTuple_GET_SIZE(val) == 1) {
|
if (exc && PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1) {
|
||||||
_PyErr_Clear(tstate);
|
_PyErr_Clear(tstate);
|
||||||
PyObject *funcstr = _PyObject_FunctionStr(func);
|
PyObject *funcstr = _PyObject_FunctionStr(func);
|
||||||
if (funcstr != NULL) {
|
if (funcstr != NULL) {
|
||||||
PyObject *key = PyTuple_GET_ITEM(val, 0);
|
PyObject *key = PyTuple_GET_ITEM(args, 0);
|
||||||
_PyErr_Format(
|
_PyErr_Format(
|
||||||
tstate, PyExc_TypeError,
|
tstate, PyExc_TypeError,
|
||||||
"%U got multiple values for keyword argument '%S'",
|
"%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_DECREF(funcstr);
|
||||||
}
|
}
|
||||||
Py_XDECREF(exc);
|
Py_XDECREF(exc);
|
||||||
Py_XDECREF(val);
|
|
||||||
Py_XDECREF(tb);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_PyErr_Restore(tstate, exc, val, tb);
|
_PyErr_SetRaisedException(tstate, exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
227
Python/errors.c
227
Python/errors.c
|
@ -27,54 +27,12 @@ static PyObject *
|
||||||
_PyErr_FormatV(PyThreadState *tstate, PyObject *exception,
|
_PyErr_FormatV(PyThreadState *tstate, PyObject *exception,
|
||||||
const char *format, va_list vargs);
|
const char *format, va_list vargs);
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_PyErr_Restore(PyThreadState *tstate, PyObject *type, PyObject *value,
|
_PyErr_SetRaisedException(PyThreadState *tstate, PyObject *exc)
|
||||||
PyObject *traceback)
|
|
||||||
{
|
{
|
||||||
PyObject *oldtype, *oldvalue, *oldtraceback;
|
PyObject *old_exc = tstate->current_exception;
|
||||||
|
tstate->current_exception = exc;
|
||||||
if (traceback != NULL && !PyTraceBack_Check(traceback)) {
|
Py_XDECREF(old_exc);
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
|
@ -103,6 +61,80 @@ _PyErr_CreateException(PyObject *exception_type, PyObject *value)
|
||||||
return exc;
|
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
|
void
|
||||||
_PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value)
|
_PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value)
|
||||||
{
|
{
|
||||||
|
@ -117,30 +149,29 @@ _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value)
|
||||||
exception);
|
exception);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_XINCREF(value);
|
Py_XINCREF(value);
|
||||||
|
/* Normalize the exception */
|
||||||
|
if (value == NULL || (PyObject *)Py_TYPE(value) != exception) {
|
||||||
|
/* We must normalize the value right now */
|
||||||
|
PyObject *fixed_value;
|
||||||
|
|
||||||
|
/* Issue #23571: functions must not be called with an
|
||||||
|
exception set */
|
||||||
|
_PyErr_Clear(tstate);
|
||||||
|
|
||||||
|
fixed_value = _PyErr_CreateException(exception, value);
|
||||||
|
Py_XDECREF(value);
|
||||||
|
if (fixed_value == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = fixed_value;
|
||||||
|
}
|
||||||
|
|
||||||
exc_value = _PyErr_GetTopmostException(tstate)->exc_value;
|
exc_value = _PyErr_GetTopmostException(tstate)->exc_value;
|
||||||
if (exc_value != NULL && exc_value != Py_None) {
|
if (exc_value != NULL && exc_value != Py_None) {
|
||||||
/* Implicit exception chaining */
|
/* Implicit exception chaining */
|
||||||
Py_INCREF(exc_value);
|
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(tstate);
|
|
||||||
|
|
||||||
fixed_value = _PyErr_CreateException(exception, value);
|
|
||||||
Py_XDECREF(value);
|
|
||||||
if (fixed_value == NULL) {
|
|
||||||
Py_DECREF(exc_value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = fixed_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Avoid creating new reference cycles through the
|
/* Avoid creating new reference cycles through the
|
||||||
context chain, while taking care not to hang on
|
context chain, while taking care not to hang on
|
||||||
pre-existing ones.
|
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
|
void
|
||||||
_PyErr_Fetch(PyThreadState *tstate, PyObject **p_type, PyObject **p_value,
|
_PyErr_Fetch(PyThreadState *tstate, PyObject **p_type, PyObject **p_value,
|
||||||
PyObject **p_traceback)
|
PyObject **p_traceback)
|
||||||
{
|
{
|
||||||
*p_type = tstate->curexc_type;
|
PyObject *exc = _PyErr_GetRaisedException(tstate);
|
||||||
*p_value = tstate->curexc_value;
|
*p_value = exc;
|
||||||
*p_traceback = tstate->curexc_traceback;
|
if (exc == NULL) {
|
||||||
|
*p_type = NULL;
|
||||||
tstate->curexc_type = NULL;
|
*p_traceback = NULL;
|
||||||
tstate->curexc_value = NULL;
|
}
|
||||||
tstate->curexc_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.
|
/* 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
|
If the provided exc_info is NULL, then the current Python thread state's
|
||||||
|
@ -706,19 +776,6 @@ PyErr_BadArgument(void)
|
||||||
return 0;
|
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 *
|
PyObject *
|
||||||
PyErr_NoMemory(void)
|
PyErr_NoMemory(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1036,9 +1036,7 @@
|
||||||
Py_DECREF(exc_value);
|
Py_DECREF(exc_value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyObject *exc_type = Py_NewRef(Py_TYPE(exc_value));
|
_PyErr_SetRaisedException(tstate, Py_NewRef(exc_value));
|
||||||
PyObject *exc_traceback = PyException_GetTraceback(exc_value);
|
|
||||||
_PyErr_Restore(tstate, exc_type, Py_NewRef(exc_value), exc_traceback);
|
|
||||||
goto exception_unwind;
|
goto exception_unwind;
|
||||||
}
|
}
|
||||||
STACK_SHRINK(2);
|
STACK_SHRINK(2);
|
||||||
|
|
|
@ -1592,6 +1592,13 @@ remove_importlib_frames(PyThreadState *tstate)
|
||||||
Py_DECREF(code);
|
Py_DECREF(code);
|
||||||
tb = next;
|
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:
|
done:
|
||||||
_PyErr_Restore(tstate, exception, value, base_tb);
|
_PyErr_Restore(tstate, exception, value, base_tb);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3143,8 +3143,7 @@ init_dump_ascii_wstr(const wchar_t *str)
|
||||||
void
|
void
|
||||||
_Py_DumpPathConfig(PyThreadState *tstate)
|
_Py_DumpPathConfig(PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
PyObject *exc_type, *exc_value, *exc_tb;
|
PyObject *exc = _PyErr_GetRaisedException(tstate);
|
||||||
_PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb);
|
|
||||||
|
|
||||||
PySys_WriteStderr("Python path configuration:\n");
|
PySys_WriteStderr("Python path configuration:\n");
|
||||||
|
|
||||||
|
@ -3202,5 +3201,5 @@ _Py_DumpPathConfig(PyThreadState *tstate)
|
||||||
PySys_WriteStderr(" ]\n");
|
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->dict);
|
||||||
Py_CLEAR(tstate->async_exc);
|
Py_CLEAR(tstate->async_exc);
|
||||||
|
|
||||||
Py_CLEAR(tstate->curexc_type);
|
Py_CLEAR(tstate->current_exception);
|
||||||
Py_CLEAR(tstate->curexc_value);
|
|
||||||
Py_CLEAR(tstate->curexc_traceback);
|
|
||||||
|
|
||||||
Py_CLEAR(tstate->exc_state.exc_value);
|
Py_CLEAR(tstate->exc_state.exc_value);
|
||||||
|
|
||||||
|
|
|
@ -748,13 +748,10 @@ _Py_HandleSystemExit(int *exitcode_p)
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
/* Restore and clear the exception info, in order to properly decref
|
/* Cleanup the exception */
|
||||||
* the exception, value, and traceback. If we just exit instead,
|
Py_CLEAR(exception);
|
||||||
* these leak, which confuses PYTHONDUMPREFS output, and may prevent
|
Py_CLEAR(value);
|
||||||
* some finalizers from running.
|
Py_CLEAR(tb);
|
||||||
*/
|
|
||||||
PyErr_Restore(exception, value, tb);
|
|
||||||
PyErr_Clear();
|
|
||||||
*exitcode_p = exitcode;
|
*exitcode_p = exitcode;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,12 +66,11 @@ _PySys_GetAttr(PyThreadState *tstate, PyObject *name)
|
||||||
if (sd == NULL) {
|
if (sd == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
PyObject *exc_type, *exc_value, *exc_tb;
|
PyObject *exc = _PyErr_GetRaisedException(tstate);
|
||||||
_PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb);
|
|
||||||
/* XXX Suppress a new exception if it was raised and restore
|
/* XXX Suppress a new exception if it was raised and restore
|
||||||
* the old one. */
|
* the old one. */
|
||||||
PyObject *value = _PyDict_GetItemWithError(sd, name);
|
PyObject *value = _PyDict_GetItemWithError(sd, name);
|
||||||
_PyErr_Restore(tstate, exc_type, exc_value, exc_tb);
|
_PyErr_SetRaisedException(tstate, exc);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3704,11 +3703,10 @@ static void
|
||||||
sys_format(PyObject *key, FILE *fp, const char *format, va_list va)
|
sys_format(PyObject *key, FILE *fp, const char *format, va_list va)
|
||||||
{
|
{
|
||||||
PyObject *file, *message;
|
PyObject *file, *message;
|
||||||
PyObject *error_type, *error_value, *error_traceback;
|
|
||||||
const char *utf8;
|
const char *utf8;
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
|
|
||||||
_PyErr_Fetch(tstate, &error_type, &error_value, &error_traceback);
|
PyObject *error = _PyErr_GetRaisedException(tstate);
|
||||||
file = _PySys_GetAttr(tstate, key);
|
file = _PySys_GetAttr(tstate, key);
|
||||||
message = PyUnicode_FromFormatV(format, va);
|
message = PyUnicode_FromFormatV(format, va);
|
||||||
if (message != NULL) {
|
if (message != NULL) {
|
||||||
|
@ -3720,7 +3718,7 @@ sys_format(PyObject *key, FILE *fp, const char *format, va_list va)
|
||||||
}
|
}
|
||||||
Py_DECREF(message);
|
Py_DECREF(message);
|
||||||
}
|
}
|
||||||
_PyErr_Restore(tstate, error_type, error_value, error_traceback);
|
_PyErr_SetRaisedException(tstate, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -249,6 +249,8 @@ PyTraceBack_Here(PyFrameObject *frame)
|
||||||
_PyErr_ChainExceptions(exc, val, tb);
|
_PyErr_ChainExceptions(exc, val, tb);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
assert(PyExceptionInstance_Check(val));
|
||||||
|
PyException_SetTraceback(val, newtb);
|
||||||
PyErr_Restore(exc, val, newtb);
|
PyErr_Restore(exc, val, newtb);
|
||||||
Py_XDECREF(tb);
|
Py_XDECREF(tb);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -260,13 +262,12 @@ void _PyTraceback_Add(const char *funcname, const char *filename, int lineno)
|
||||||
PyObject *globals;
|
PyObject *globals;
|
||||||
PyCodeObject *code;
|
PyCodeObject *code;
|
||||||
PyFrameObject *frame;
|
PyFrameObject *frame;
|
||||||
PyObject *exc, *val, *tb;
|
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
|
|
||||||
/* Save and clear the current exception. Python functions must not be
|
/* Save and clear the current exception. Python functions must not be
|
||||||
called with an exception set. Calling Python functions happens when
|
called with an exception set. Calling Python functions happens when
|
||||||
the codec of the filesystem encoding is implemented in pure Python. */
|
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();
|
globals = PyDict_New();
|
||||||
if (!globals)
|
if (!globals)
|
||||||
|
@ -283,13 +284,13 @@ void _PyTraceback_Add(const char *funcname, const char *filename, int lineno)
|
||||||
goto error;
|
goto error;
|
||||||
frame->f_lineno = lineno;
|
frame->f_lineno = lineno;
|
||||||
|
|
||||||
_PyErr_Restore(tstate, exc, val, tb);
|
_PyErr_SetRaisedException(tstate, exc);
|
||||||
PyTraceBack_Here(frame);
|
PyTraceBack_Here(frame);
|
||||||
Py_DECREF(frame);
|
Py_DECREF(frame);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
_PyErr_ChainExceptions(exc, val, tb);
|
_PyErr_ChainExceptions1(exc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
|
Loading…
Reference in New Issue