bpo-45711: Remove type and traceback from exc_info (GH-30122)

* Do not PUSH/POP traceback or type to the stack as part of exc_info

* Remove exc_traceback and exc_type from _PyErr_StackItem

* Add to what's new, because this change breaks things like Cython
This commit is contained in:
Irit Katriel 2021-12-17 14:46:22 +00:00 committed by GitHub
parent 62a0a2a25d
commit 396b58345f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 228 additions and 389 deletions

View File

@ -474,13 +474,15 @@ the original TOS1.
.. opcode:: END_ASYNC_FOR .. opcode:: END_ASYNC_FOR
Terminates an :keyword:`async for` loop. Handles an exception raised Terminates an :keyword:`async for` loop. Handles an exception raised
when awaiting a next item. If TOS is :exc:`StopAsyncIteration` pop 7 when awaiting a next item. If TOS is :exc:`StopAsyncIteration` pop 3
values from the stack and restore the exception state using the second values from the stack and restore the exception state using the second
three of them. Otherwise re-raise the exception using the three values of them. Otherwise re-raise the exception using the value
from the stack. An exception handler block is removed from the block stack. from the stack. An exception handler block is removed from the block stack.
.. versionadded:: 3.8 .. versionadded:: 3.8
.. versionchanged:: 3.11
Exception representation on the stack now consist of one, not three, items.
.. opcode:: BEFORE_ASYNC_WITH .. opcode:: BEFORE_ASYNC_WITH
@ -561,8 +563,10 @@ iterations of the loop.
.. opcode:: POP_EXCEPT .. opcode:: POP_EXCEPT
Pops three values from the stack, which are used to restore the exception state. Pops a value from the stack, which is used to restore the exception state.
.. versionchanged:: 3.11
Exception representation on the stack now consist of one, not three, items.
.. opcode:: RERAISE .. opcode:: RERAISE
@ -572,11 +576,13 @@ iterations of the loop.
.. versionadded:: 3.9 .. versionadded:: 3.9
.. versionchanged:: 3.11
Exception representation on the stack now consist of one, not three, items.
.. opcode:: PUSH_EXC_INFO .. opcode:: PUSH_EXC_INFO
Pops the three values from the stack. Pushes the current exception to the top of the stack. Pops a value from the stack. Pushes the current exception to the top of the stack.
Pushes the three values originally popped back to the stack. Pushes the value originally popped back to the stack.
Used in exception handlers. Used in exception handlers.
.. versionadded:: 3.11 .. versionadded:: 3.11
@ -584,8 +590,8 @@ iterations of the loop.
.. opcode:: WITH_EXCEPT_START .. opcode:: WITH_EXCEPT_START
Calls the function in position 8 on the stack with the top three Calls the function in position 4 on the stack with arguments (type, val, tb)
items on the stack as arguments. representing the exception at the top of the stack.
Used to implement the call ``context_manager.__exit__(*exc_info())`` when an exception Used to implement the call ``context_manager.__exit__(*exc_info())`` when an exception
has occurred in a :keyword:`with` statement. has occurred in a :keyword:`with` statement.
@ -593,6 +599,9 @@ iterations of the loop.
.. versionchanged:: 3.11 .. versionchanged:: 3.11
The ``__exit__`` function is in position 8 of the stack rather than 7. The ``__exit__`` function is in position 8 of the stack rather than 7.
.. versionchanged:: 3.11
The ``__exit__`` function is in position 4 of the stack rather than 7.
Exception representation on the stack now consist of one, not three, items.
.. opcode:: POP_EXCEPT_AND_RERAISE .. opcode:: POP_EXCEPT_AND_RERAISE
@ -890,10 +899,9 @@ All of the following opcodes use their arguments.
Performs exception matching for ``except*``. Applies ``split(TOS)`` on Performs exception matching for ``except*``. Applies ``split(TOS)`` on
the exception group representing TOS1. Jumps if no match is found. the exception group representing TOS1. Jumps if no match is found.
Pops one item from the stack. If a match was found, pops the 3 items representing Pops one item from the stack (the match type). If a match was found,
the exception and pushes the 3 items representing the non-matching part of next item (the exception) and pushes the non-matching part of the
the exception group, followed by the 3 items representing the matching part. exception group followed by the matching part.
In other words, in case of a match it pops 4 items and pushes 6.
.. versionadded:: 3.11 .. versionadded:: 3.11
@ -903,8 +911,8 @@ All of the following opcodes use their arguments.
Combines the raised and reraised exceptions list from TOS, into an exception Combines the raised and reraised exceptions list from TOS, into an exception
group to propagate from a try-except* block. Uses the original exception group to propagate from a try-except* block. Uses the original exception
group from TOS1 to reconstruct the structure of reraised exceptions. Pops group from TOS1 to reconstruct the structure of reraised exceptions. Pops
two items from the stack and pushes a triplet representing the exception to two items from the stack and pushes 0 (for lasti, which is unused) followed
reraise or three ``None`` if there isn't one. by the exception to reraise or ``None`` if there isn't one.
.. versionadded:: 3.11 .. versionadded:: 3.11

View File

@ -195,6 +195,11 @@ Other CPython Implementation Changes
reflected in the re-raised exception. reflected in the re-raised exception.
(Contributed by Irit Katriel in :issue:`45711`.) (Contributed by Irit Katriel in :issue:`45711`.)
* The interpreter state's representation of handled exceptions (a.k.a exc_info, or
_PyErr_StackItem) now has only the ``exc_value`` field, ``exc_type`` and ``exc_traceback``
have been removed as their values can be derived from ``exc_value``.
(Contributed by Irit Katriel in :issue:`45711`.)
New Modules New Modules
=========== ===========

View File

@ -56,7 +56,7 @@ typedef struct _err_stackitem {
* This ensures that the exception state is not impacted by "yields" * This ensures that the exception state is not impacted by "yields"
* from an except handler. * from an except handler.
*/ */
PyObject *exc_type, *exc_value, *exc_traceback; PyObject *exc_value;
struct _err_stackitem *previous_item; struct _err_stackitem *previous_item;

View File

@ -24,16 +24,7 @@ static inline PyObject* _PyErr_Occurred(PyThreadState *tstate)
static inline void _PyErr_ClearExcState(_PyErr_StackItem *exc_state) static inline void _PyErr_ClearExcState(_PyErr_StackItem *exc_state)
{ {
PyObject *t, *v, *tb; Py_CLEAR(exc_state->exc_value);
t = exc_state->exc_type;
v = exc_state->exc_value;
tb = exc_state->exc_traceback;
exc_state->exc_type = NULL;
exc_state->exc_value = NULL;
exc_state->exc_traceback = NULL;
Py_XDECREF(t);
Py_XDECREF(v);
Py_XDECREF(tb);
} }
PyAPI_FUNC(PyObject*) _PyErr_StackItemToExcInfoTuple( PyAPI_FUNC(PyObject*) _PyErr_StackItemToExcInfoTuple(
@ -114,6 +105,7 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc(
#define _Py_FatalRefcountError(message) _Py_FatalRefcountErrorFunc(__func__, message) #define _Py_FatalRefcountError(message) _Py_FatalRefcountErrorFunc(__func__, message)
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -371,9 +371,10 @@ _code_type = type(_write_atomic.__code__)
# Python 3.11a3 3464 (bpo-45636: Merge numeric BINARY_*/INPLACE_* into # Python 3.11a3 3464 (bpo-45636: Merge numeric BINARY_*/INPLACE_* into
# BINARY_OP) # BINARY_OP)
# Python 3.11a3 3465 (Add COPY_FREE_VARS opcode) # Python 3.11a3 3465 (Add COPY_FREE_VARS opcode)
# Python 3.11a3 3466 (bpo-45292: PEP-654 except*) # Python 3.11a4 3466 (bpo-45292: PEP-654 except*)
# Python 3.11a4 3467 (Change CALL_xxx opcodes) # Python 3.11a4 3467 (Change CALL_xxx opcodes)
# Python 3.11a4 3468 (Add SEND opcode) # Python 3.11a4 3468 (Add SEND opcode)
# Python 3.11a4 3469 (bpo-45711: remove type, traceback from exc_info)
# #
# MAGIC must change whenever the bytecode emitted by the compiler may no # MAGIC must change whenever the bytecode emitted by the compiler may no
@ -383,7 +384,7 @@ _code_type = type(_write_atomic.__code__)
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated. # in PC/launcher.c must also be updated.
MAGIC_NUMBER = (3468).to_bytes(2, 'little') + b'\r\n' MAGIC_NUMBER = (3469).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__' _PYCACHE = '__pycache__'

View File

@ -310,33 +310,31 @@ dis_traceback = """\
>> 14 PUSH_EXC_INFO >> 14 PUSH_EXC_INFO
%3d 16 LOAD_GLOBAL 0 (Exception) %3d 16 LOAD_GLOBAL 0 (Exception)
18 JUMP_IF_NOT_EXC_MATCH 26 (to 52) 18 JUMP_IF_NOT_EXC_MATCH 24 (to 48)
20 POP_TOP 20 STORE_FAST 0 (e)
22 STORE_FAST 0 (e)
24 POP_TOP
%3d 26 LOAD_FAST 0 (e) %3d 22 LOAD_FAST 0 (e)
28 LOAD_ATTR 1 (__traceback__) 24 LOAD_ATTR 1 (__traceback__)
30 STORE_FAST 1 (tb) 26 STORE_FAST 1 (tb)
32 POP_EXCEPT 28 POP_EXCEPT
34 LOAD_CONST 0 (None) 30 LOAD_CONST 0 (None)
36 STORE_FAST 0 (e) 32 STORE_FAST 0 (e)
38 DELETE_FAST 0 (e) 34 DELETE_FAST 0 (e)
%3d 40 LOAD_FAST 1 (tb) %3d 36 LOAD_FAST 1 (tb)
42 RETURN_VALUE 38 RETURN_VALUE
>> 44 LOAD_CONST 0 (None) >> 40 LOAD_CONST 0 (None)
46 STORE_FAST 0 (e) 42 STORE_FAST 0 (e)
48 DELETE_FAST 0 (e) 44 DELETE_FAST 0 (e)
50 RERAISE 1 46 RERAISE 1
%3d >> 52 RERAISE 0 %3d >> 48 RERAISE 0
>> 54 POP_EXCEPT_AND_RERAISE >> 50 POP_EXCEPT_AND_RERAISE
ExceptionTable: ExceptionTable:
2 to 8 -> 14 [0] 2 to 8 -> 14 [0]
14 to 24 -> 54 [3] lasti 14 to 20 -> 50 [1] lasti
26 to 30 -> 44 [3] lasti 22 to 26 -> 40 [1] lasti
44 to 52 -> 54 [3] lasti 40 to 48 -> 50 [1] lasti
""" % (TRACEBACK_CODE.co_firstlineno + 1, """ % (TRACEBACK_CODE.co_firstlineno + 1,
TRACEBACK_CODE.co_firstlineno + 2, TRACEBACK_CODE.co_firstlineno + 2,
TRACEBACK_CODE.co_firstlineno + 5, TRACEBACK_CODE.co_firstlineno + 5,
@ -395,7 +393,7 @@ dis_tryfinally = """\
>> 22 POP_EXCEPT_AND_RERAISE >> 22 POP_EXCEPT_AND_RERAISE
ExceptionTable: ExceptionTable:
2 to 2 -> 12 [0] 2 to 2 -> 12 [0]
12 to 20 -> 22 [3] lasti 12 to 20 -> 22 [1] lasti
""" % (_tryfinally.__code__.co_firstlineno + 1, """ % (_tryfinally.__code__.co_firstlineno + 1,
_tryfinally.__code__.co_firstlineno + 2, _tryfinally.__code__.co_firstlineno + 2,
_tryfinally.__code__.co_firstlineno + 4, _tryfinally.__code__.co_firstlineno + 4,
@ -418,7 +416,7 @@ dis_tryfinallyconst = """\
22 RERAISE 0 22 RERAISE 0
>> 24 POP_EXCEPT_AND_RERAISE >> 24 POP_EXCEPT_AND_RERAISE
ExceptionTable: ExceptionTable:
14 to 22 -> 24 [3] lasti 14 to 22 -> 24 [1] lasti
""" % (_tryfinallyconst.__code__.co_firstlineno + 1, """ % (_tryfinallyconst.__code__.co_firstlineno + 1,
_tryfinallyconst.__code__.co_firstlineno + 2, _tryfinallyconst.__code__.co_firstlineno + 2,
_tryfinallyconst.__code__.co_firstlineno + 4, _tryfinallyconst.__code__.co_firstlineno + 4,
@ -864,7 +862,7 @@ Argument count: 0
Positional-only arguments: 0 Positional-only arguments: 0
Kw-only arguments: 0 Kw-only arguments: 0
Number of locals: 2 Number of locals: 2
Stack size: 10 Stack size: 6
Flags: OPTIMIZED, NEWLOCALS, COROUTINE Flags: OPTIMIZED, NEWLOCALS, COROUTINE
Constants: Constants:
0: None 0: None
@ -1107,65 +1105,61 @@ expected_opinfo_jumpy = [
Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=108, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=108, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=110, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=110, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=14, argval=144, argrepr='to 144', offset=114, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=12, argval=140, argrepr='to 140', offset=114, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=116, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=116, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=118, starts_line=22, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=118, starts_line=22, is_jump_target=False, positions=None),
Instruction(opname='JUMP_IF_NOT_EXC_MATCH', opcode=121, arg=70, argval=140, argrepr='to 140', offset=120, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_IF_NOT_EXC_MATCH', opcode=121, arg=68, argval=136, argrepr='to 136', offset=120, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=122, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=122, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=124, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=124, starts_line=23, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=126, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=126, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=128, starts_line=23, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=128, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=130, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=130, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=132, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=132, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=134, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=30, argval=196, argrepr='to 196', offset=134, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=136, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=136, starts_line=22, is_jump_target=True, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=32, argval=204, argrepr='to 204', offset=138, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=138, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=140, starts_line=22, is_jump_target=True, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=140, starts_line=25, is_jump_target=True, positions=None),
Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=142, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=142, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=144, starts_line=25, is_jump_target=True, positions=None), Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=144, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=146, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=146, starts_line=26, is_jump_target=False, positions=None),
Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=148, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=148, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=150, starts_line=26, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=150, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=152, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=152, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=154, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=154, starts_line=25, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=156, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=156, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=158, starts_line=25, is_jump_target=False, positions=None), Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=158, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=160, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=3, argval=3, argrepr='', offset=160, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=162, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=162, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_NO_KW', opcode=169, arg=3, argval=3, argrepr='', offset=164, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=9, argval=184, argrepr='to 184', offset=164, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=192, argrepr='to 192', offset=168, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=168, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=170, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=88, argval=176, argrepr='to 176', offset=170, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=172, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=90, argval=180, argrepr='to 180', offset=174, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=174, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=4, argval=4, argrepr='', offset=176, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=176, starts_line=None, is_jump_target=True, positions=None),
Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=178, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=178, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=180, starts_line=None, is_jump_target=True, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=180, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=182, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=182, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=184, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=184, starts_line=28, is_jump_target=True, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=186, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=186, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=188, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=188, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=190, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=190, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=192, starts_line=28, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=192, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=194, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=194, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=196, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=196, starts_line=23, is_jump_target=True, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=198, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=198, starts_line=28, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=200, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=200, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=202, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=202, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=204, starts_line=23, is_jump_target=True, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=204, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=206, starts_line=28, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=206, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=208, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=208, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=210, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=210, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=212, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=212, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=214, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=214, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=216, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=216, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=218, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=218, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=220, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=220, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=222, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=222, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=224, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=226, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=228, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=230, starts_line=None, is_jump_target=False, positions=None),
] ]
# One last piece of inspect fodder to check the default line number handling # One last piece of inspect fodder to check the default line number handling

View File

@ -1340,7 +1340,7 @@ class SizeofTest(unittest.TestCase):
check(bar, size('PP')) check(bar, size('PP'))
# generator # generator
def get_gen(): yield 1 def get_gen(): yield 1
check(get_gen(), size('P2PPP4P4c8P2iciP')) check(get_gen(), size('P2P4P4c8P2iciP'))
# iterator # iterator
check(iter('abc'), size('lP')) check(iter('abc'), size('lP'))
# callable-iterator # callable-iterator

View File

@ -0,0 +1 @@
The interpreter state's representation of handled exceptions (a.k.a exc_info, or _PyErr_StackItem) now has only the ``exc_value`` field, ``exc_type`` and ``exc_traceback`` have been removed as their values can be derived from ``exc_value``.

View File

@ -810,9 +810,7 @@ FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg)
Py_VISIT(fut->dict); Py_VISIT(fut->dict);
_PyErr_StackItem *exc_state = &fut->fut_cancelled_exc_state; _PyErr_StackItem *exc_state = &fut->fut_cancelled_exc_state;
Py_VISIT(exc_state->exc_type);
Py_VISIT(exc_state->exc_value); Py_VISIT(exc_state->exc_value);
Py_VISIT(exc_state->exc_traceback);
return 0; return 0;
} }
@ -1376,10 +1374,6 @@ _asyncio_Future__make_cancelled_error_impl(FutureObj *self)
PyException_SetContext(exc, Py_NewRef(exc_state->exc_value)); PyException_SetContext(exc, Py_NewRef(exc_state->exc_value));
_PyErr_ClearExcState(exc_state); _PyErr_ClearExcState(exc_state);
} }
else {
assert(exc_state->exc_type == NULL);
assert(exc_state->exc_traceback == NULL);
}
return exc; return exc;
} }
@ -2706,13 +2700,13 @@ task_step_impl(TaskObj *task, PyObject *exc)
PyErr_NormalizeException(&et, &ev, &tb); PyErr_NormalizeException(&et, &ev, &tb);
if (tb != NULL) { if (tb != NULL) {
PyException_SetTraceback(ev, tb); PyException_SetTraceback(ev, tb);
Py_DECREF(tb);
} }
Py_XDECREF(et);
FutureObj *fut = (FutureObj*)task; FutureObj *fut = (FutureObj*)task;
_PyErr_StackItem *exc_state = &fut->fut_cancelled_exc_state; _PyErr_StackItem *exc_state = &fut->fut_cancelled_exc_state;
exc_state->exc_type = et;
exc_state->exc_value = ev; exc_state->exc_value = ev;
exc_state->exc_traceback = tb;
return future_cancel(fut, NULL); return future_cancel(fut, NULL);
} }

View File

@ -25,9 +25,7 @@ static const char *ASYNC_GEN_IGNORED_EXIT_MSG =
static inline int static inline int
exc_state_traverse(_PyErr_StackItem *exc_state, visitproc visit, void *arg) exc_state_traverse(_PyErr_StackItem *exc_state, visitproc visit, void *arg)
{ {
Py_VISIT(exc_state->exc_type);
Py_VISIT(exc_state->exc_value); Py_VISIT(exc_state->exc_value);
Py_VISIT(exc_state->exc_traceback);
return 0; return 0;
} }
@ -886,9 +884,7 @@ make_gen(PyTypeObject *type, PyFunctionObject *func)
gen->gi_code = (PyCodeObject *)func->func_code; gen->gi_code = (PyCodeObject *)func->func_code;
Py_INCREF(gen->gi_code); Py_INCREF(gen->gi_code);
gen->gi_weakreflist = NULL; gen->gi_weakreflist = NULL;
gen->gi_exc_state.exc_type = NULL;
gen->gi_exc_state.exc_value = NULL; gen->gi_exc_state.exc_value = NULL;
gen->gi_exc_state.exc_traceback = NULL;
gen->gi_exc_state.previous_item = NULL; gen->gi_exc_state.previous_item = NULL;
if (func->func_name != NULL) if (func->func_name != NULL)
gen->gi_name = func->func_name; gen->gi_name = func->func_name;
@ -975,9 +971,7 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
Py_INCREF(gen->gi_code); Py_INCREF(gen->gi_code);
Py_DECREF(f); Py_DECREF(f);
gen->gi_weakreflist = NULL; gen->gi_weakreflist = NULL;
gen->gi_exc_state.exc_type = NULL;
gen->gi_exc_state.exc_value = NULL; gen->gi_exc_state.exc_value = NULL;
gen->gi_exc_state.exc_traceback = NULL;
gen->gi_exc_state.previous_item = NULL; gen->gi_exc_state.previous_item = NULL;
if (name != NULL) if (name != NULL)
gen->gi_name = name; gen->gi_name = name;

View File

@ -1094,29 +1094,11 @@ fail:
static int do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause); static int do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause);
static PyObject *do_reraise_star(PyObject *excs, PyObject *orig); static PyObject *do_reraise_star(PyObject *excs, PyObject *orig);
static int exception_group_match( static int exception_group_match(
PyObject *exc_type, PyObject* exc_value, PyObject *match_type, PyObject* exc_value, PyObject *match_type,
PyObject **match, PyObject **rest); PyObject **match, PyObject **rest);
static int unpack_iterable(PyThreadState *, PyObject *, int, int, PyObject **); static int unpack_iterable(PyThreadState *, PyObject *, int, int, PyObject **);
#ifdef Py_DEBUG
static void
_assert_exception_type_is_redundant(PyObject* type, PyObject* val)
{
if (type == NULL || type == Py_None) {
assert(val == type);
}
else {
assert(PyExceptionInstance_Check(val));
assert(PyExceptionInstance_Class(val) == type);
}
}
#define ASSERT_EXC_TYPE_IS_REDUNDANT(t, v) _assert_exception_type_is_redundant(t, v)
#else
#define ASSERT_EXC_TYPE_IS_REDUNDANT(t, v)
#endif
PyObject * PyObject *
PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals) PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals)
{ {
@ -2737,25 +2719,15 @@ check_eval_breaker:
} }
TARGET(POP_EXCEPT) { TARGET(POP_EXCEPT) {
PyObject *type, *value, *traceback; _PyErr_StackItem *exc_info = tstate->exc_info;
_PyErr_StackItem *exc_info; PyObject *value = exc_info->exc_value;
exc_info = tstate->exc_info;
type = exc_info->exc_type;
value = exc_info->exc_value;
traceback = exc_info->exc_traceback;
exc_info->exc_type = POP();
exc_info->exc_value = POP(); exc_info->exc_value = POP();
exc_info->exc_traceback = POP();
ASSERT_EXC_TYPE_IS_REDUNDANT(exc_info->exc_type, exc_info->exc_value);
Py_XDECREF(type);
Py_XDECREF(value); Py_XDECREF(value);
Py_XDECREF(traceback);
DISPATCH(); DISPATCH();
} }
TARGET(POP_EXCEPT_AND_RERAISE) { TARGET(POP_EXCEPT_AND_RERAISE) {
PyObject *lasti = PEEK(4); PyObject *lasti = PEEK(2);
if (PyLong_Check(lasti)) { if (PyLong_Check(lasti)) {
frame->f_lasti = PyLong_AsLong(lasti); frame->f_lasti = PyLong_AsLong(lasti);
assert(!_PyErr_Occurred(tstate)); assert(!_PyErr_Occurred(tstate));
@ -2764,31 +2736,24 @@ check_eval_breaker:
_PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int"); _PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int");
goto error; goto error;
} }
PyObject *type, *value, *traceback; PyObject *value = POP();
_PyErr_StackItem *exc_info; assert(value);
type = POP(); assert(PyExceptionInstance_Check(value));
value = POP(); PyObject *type = Py_NewRef(PyExceptionInstance_Class(value));
traceback = POP(); PyObject *traceback = PyException_GetTraceback(value);
ASSERT_EXC_TYPE_IS_REDUNDANT(type, value);
Py_DECREF(POP()); /* lasti */ Py_DECREF(POP()); /* lasti */
_PyErr_Restore(tstate, type, value, traceback); _PyErr_Restore(tstate, type, value, traceback);
exc_info = tstate->exc_info;
type = exc_info->exc_type; _PyErr_StackItem *exc_info = tstate->exc_info;
value = exc_info->exc_value; value = exc_info->exc_value;
traceback = exc_info->exc_traceback;
exc_info->exc_type = POP();
exc_info->exc_value = POP(); exc_info->exc_value = POP();
exc_info->exc_traceback = POP();
ASSERT_EXC_TYPE_IS_REDUNDANT(exc_info->exc_type, exc_info->exc_value);
Py_XDECREF(type);
Py_XDECREF(value); Py_XDECREF(value);
Py_XDECREF(traceback);
goto exception_unwind; goto exception_unwind;
} }
TARGET(RERAISE) { TARGET(RERAISE) {
if (oparg) { if (oparg) {
PyObject *lasti = PEEK(oparg+3); PyObject *lasti = PEEK(oparg + 1);
if (PyLong_Check(lasti)) { if (PyLong_Check(lasti)) {
frame->f_lasti = PyLong_AsLong(lasti); frame->f_lasti = PyLong_AsLong(lasti);
assert(!_PyErr_Occurred(tstate)); assert(!_PyErr_Occurred(tstate));
@ -2799,11 +2764,10 @@ check_eval_breaker:
goto error; goto error;
} }
} }
PyObject *exc = POP();
PyObject *val = POP(); PyObject *val = POP();
PyObject *tb = POP(); assert(val && PyExceptionInstance_Check(val));
ASSERT_EXC_TYPE_IS_REDUNDANT(exc, val); PyObject *exc = Py_NewRef(PyExceptionInstance_Class(val));
assert(PyExceptionClass_Check(exc)); PyObject *tb = PyException_GetTraceback(val);
_PyErr_Restore(tstate, exc, val, tb); _PyErr_Restore(tstate, exc, val, tb);
goto exception_unwind; goto exception_unwind;
} }
@ -2823,35 +2787,21 @@ check_eval_breaker:
PyObject *lasti_unused = Py_NewRef(_PyLong_GetZero()); PyObject *lasti_unused = Py_NewRef(_PyLong_GetZero());
PUSH(lasti_unused); PUSH(lasti_unused);
if (!Py_IsNone(val)) { PUSH(val);
PyObject *tb = PyException_GetTraceback(val);
PUSH(tb ? tb : Py_NewRef(Py_None));
PUSH(val);
PUSH(Py_NewRef(Py_TYPE(val)));
}
else {
// nothing to reraise
PUSH(Py_NewRef(Py_None));
PUSH(val);
PUSH(Py_NewRef(Py_None));
}
DISPATCH(); DISPATCH();
} }
TARGET(END_ASYNC_FOR) { TARGET(END_ASYNC_FOR) {
PyObject *exc = POP();
PyObject *val = POP(); PyObject *val = POP();
PyObject *tb = POP(); assert(val && PyExceptionInstance_Check(val));
ASSERT_EXC_TYPE_IS_REDUNDANT(exc, val); if (PyErr_GivenExceptionMatches(val, PyExc_StopAsyncIteration)) {
assert(PyExceptionClass_Check(exc));
if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) {
Py_DECREF(exc);
Py_DECREF(val); Py_DECREF(val);
Py_DECREF(tb);
Py_DECREF(POP()); Py_DECREF(POP());
DISPATCH(); DISPATCH();
} }
else { else {
PyObject *exc = Py_NewRef(PyExceptionInstance_Class(val));
PyObject *tb = PyException_GetTraceback(val);
_PyErr_Restore(tstate, exc, val, tb); _PyErr_Restore(tstate, exc, val, tb);
goto exception_unwind; goto exception_unwind;
} }
@ -3971,16 +3921,15 @@ check_eval_breaker:
TARGET(JUMP_IF_NOT_EG_MATCH) { TARGET(JUMP_IF_NOT_EG_MATCH) {
PyObject *match_type = POP(); PyObject *match_type = POP();
PyObject *exc_type = TOP();
PyObject *exc_value = SECOND();
if (check_except_star_type_valid(tstate, match_type) < 0) { if (check_except_star_type_valid(tstate, match_type) < 0) {
Py_DECREF(match_type); Py_DECREF(match_type);
goto error; goto error;
} }
PyObject *exc_value = TOP();
PyObject *match = NULL, *rest = NULL; PyObject *match = NULL, *rest = NULL;
int res = exception_group_match(exc_type, exc_value, int res = exception_group_match(exc_value, match_type,
match_type, &match, &rest); &match, &rest);
Py_DECREF(match_type); Py_DECREF(match_type);
if (res < 0) { if (res < 0) {
goto error; goto error;
@ -4001,46 +3950,21 @@ check_eval_breaker:
else { else {
/* Total or partial match - update the stack from /* Total or partial match - update the stack from
* [tb, val, exc] * [val]
* to * to
* [tb, rest, exc, tb, match, exc] * [rest, match]
* (rest can be Py_None) * (rest can be Py_None)
*/ */
PyObject *exc = TOP();
PyObject *type = TOP(); SET_TOP(rest);
PyObject *val = SECOND(); PUSH(match);
PyObject *tb = THIRD();
if (!Py_IsNone(rest)) { PyErr_SetExcInfo(NULL, Py_NewRef(match), NULL);
/* tb remains the same */
SET_TOP(Py_NewRef(Py_TYPE(rest)));
SET_SECOND(Py_NewRef(rest));
SET_THIRD(Py_NewRef(tb));
}
else {
SET_TOP(Py_NewRef(Py_None));
SET_SECOND(Py_NewRef(Py_None));
SET_THIRD(Py_NewRef(Py_None));
}
/* Push match */
PUSH(Py_NewRef(tb)); Py_DECREF(exc);
PUSH(Py_NewRef(match));
PUSH(Py_NewRef(Py_TYPE(match)));
// set exc_info to the current match
PyErr_SetExcInfo(
Py_NewRef(Py_TYPE(match)),
Py_NewRef(match),
Py_NewRef(tb));
Py_DECREF(tb);
Py_DECREF(val);
Py_DECREF(type);
Py_DECREF(match);
Py_DECREF(rest);
} }
DISPATCH(); DISPATCH();
@ -4048,8 +3972,7 @@ check_eval_breaker:
TARGET(JUMP_IF_NOT_EXC_MATCH) { TARGET(JUMP_IF_NOT_EXC_MATCH) {
PyObject *right = POP(); PyObject *right = POP();
ASSERT_EXC_TYPE_IS_REDUNDANT(TOP(), SECOND()); PyObject *left = TOP();
PyObject *left = SECOND();
assert(PyExceptionInstance_Check(left)); assert(PyExceptionInstance_Check(left));
if (check_except_type_valid(tstate, right) < 0) { if (check_except_type_valid(tstate, right) < 0) {
Py_DECREF(right); Py_DECREF(right);
@ -4465,26 +4388,24 @@ check_eval_breaker:
} }
TARGET(WITH_EXCEPT_START) { TARGET(WITH_EXCEPT_START) {
/* At the top of the stack are 8 values: /* At the top of the stack are 4 values:
- (TOP, SECOND, THIRD) = exc_info() - TOP = exc_info()
- (FOURTH, FIFTH, SIXTH) = previous exception - SECOND = previous exception
- SEVENTH: lasti of exception in exc_info() - THIRD: lasti of exception in exc_info()
- EIGHTH: the context.__exit__ bound method - FOURTH: the context.__exit__ bound method
We call EIGHTH(TOP, SECOND, THIRD). We call FOURTH(type(TOP), TOP, GetTraceback(TOP)).
Then we push again the TOP exception and the __exit__ Then we push the __exit__ return value.
return value.
*/ */
PyObject *exit_func; PyObject *exit_func;
PyObject *exc, *val, *tb, *res; PyObject *exc, *val, *tb, *res;
exc = TOP(); val = TOP();
val = SECOND(); assert(val && PyExceptionInstance_Check(val));
tb = THIRD(); exc = PyExceptionInstance_Class(val);
ASSERT_EXC_TYPE_IS_REDUNDANT(exc, val); tb = PyException_GetTraceback(val);
assert(!Py_IsNone(exc)); Py_XDECREF(tb);
assert(!PyLong_Check(exc)); assert(PyLong_Check(PEEK(3)));
assert(PyLong_Check(PEEK(7))); exit_func = PEEK(4);
exit_func = PEEK(8);
PyObject *stack[4] = {NULL, exc, val, tb}; PyObject *stack[4] = {NULL, exc, val, tb};
res = PyObject_Vectorcall(exit_func, stack + 1, res = PyObject_Vectorcall(exit_func, stack + 1,
3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL);
@ -4496,40 +4417,22 @@ check_eval_breaker:
} }
TARGET(PUSH_EXC_INFO) { TARGET(PUSH_EXC_INFO) {
PyObject *type = TOP(); PyObject *value = TOP();
PyObject *value = SECOND();
PyObject *tb = THIRD();
ASSERT_EXC_TYPE_IS_REDUNDANT(type, value);
_PyErr_StackItem *exc_info = tstate->exc_info; _PyErr_StackItem *exc_info = tstate->exc_info;
SET_THIRD(exc_info->exc_traceback);
if (exc_info->exc_value != NULL) { if (exc_info->exc_value != NULL) {
SET_SECOND(exc_info->exc_value); SET_TOP(exc_info->exc_value);
}
else {
Py_INCREF(Py_None);
SET_SECOND(Py_None);
}
if (exc_info->exc_type != NULL) {
SET_TOP(exc_info->exc_type);
} }
else { else {
Py_INCREF(Py_None); Py_INCREF(Py_None);
SET_TOP(Py_None); SET_TOP(Py_None);
} }
Py_INCREF(tb);
PUSH(tb);
exc_info->exc_traceback = tb;
Py_INCREF(value); Py_INCREF(value);
PUSH(value); PUSH(value);
assert(PyExceptionInstance_Check(value)); assert(PyExceptionInstance_Check(value));
exc_info->exc_value = value; exc_info->exc_value = value;
Py_INCREF(type);
PUSH(type);
assert(PyExceptionClass_Check(type));
exc_info->exc_type = type;
DISPATCH(); DISPATCH();
} }
@ -5518,14 +5421,9 @@ exception_unwind:
PyException_SetTraceback(val, tb); PyException_SetTraceback(val, tb);
else else
PyException_SetTraceback(val, Py_None); PyException_SetTraceback(val, Py_None);
if (tb == NULL) { Py_XDECREF(tb);
tb = Py_None; Py_XDECREF(exc);
Py_INCREF(Py_None);
}
PUSH(tb);
PUSH(val); PUSH(val);
PUSH(exc);
ASSERT_EXC_TYPE_IS_REDUNDANT(exc, val);
JUMPTO(handler); JUMPTO(handler);
/* Resume normal execution */ /* Resume normal execution */
frame->f_state = FRAME_EXECUTING; frame->f_state = FRAME_EXECUTING;
@ -6375,19 +6273,17 @@ raise_error:
*/ */
static int static int
exception_group_match(PyObject *exc_type, PyObject* exc_value, exception_group_match(PyObject* exc_value, PyObject *match_type,
PyObject *match_type, PyObject **match, PyObject **rest) PyObject **match, PyObject **rest)
{ {
if (Py_IsNone(exc_type)) { if (Py_IsNone(exc_value)) {
assert(Py_IsNone(exc_value));
*match = Py_NewRef(Py_None); *match = Py_NewRef(Py_None);
*rest = Py_NewRef(Py_None); *rest = Py_NewRef(Py_None);
return 0; return 0;
} }
assert(PyExceptionClass_Check(exc_type));
assert(PyExceptionInstance_Check(exc_value)); assert(PyExceptionInstance_Check(exc_value));
if (PyErr_GivenExceptionMatches(exc_type, match_type)) { if (PyErr_GivenExceptionMatches(exc_value, match_type)) {
/* Full match of exc itself */ /* Full match of exc itself */
bool is_eg = _PyBaseExceptionGroup_Check(exc_value); bool is_eg = _PyBaseExceptionGroup_Check(exc_value);
if (is_eg) { if (is_eg) {

View File

@ -1048,9 +1048,9 @@ stack_effect(int opcode, int oparg, int jump)
case POP_BLOCK: case POP_BLOCK:
return 0; return 0;
case POP_EXCEPT: case POP_EXCEPT:
return -3; return -1;
case POP_EXCEPT_AND_RERAISE: case POP_EXCEPT_AND_RERAISE:
return -7; return -3;
case STORE_NAME: case STORE_NAME:
return -1; return -1;
@ -1095,7 +1095,7 @@ stack_effect(int opcode, int oparg, int jump)
case JUMP_IF_NOT_EXC_MATCH: case JUMP_IF_NOT_EXC_MATCH:
return -1; return -1;
case JUMP_IF_NOT_EG_MATCH: case JUMP_IF_NOT_EG_MATCH:
return jump > 0 ? -1 : 2; return jump > 0 ? -1 : 0;
case IMPORT_NAME: case IMPORT_NAME:
return -1; return -1;
case IMPORT_FROM: case IMPORT_FROM:
@ -1120,25 +1120,25 @@ stack_effect(int opcode, int oparg, int jump)
/* Exception handling pseudo-instructions */ /* Exception handling pseudo-instructions */
case SETUP_FINALLY: case SETUP_FINALLY:
/* 0 in the normal flow. /* 0 in the normal flow.
* Restore the stack position and push 3 values before jumping to * Restore the stack position and push 1 value before jumping to
* the handler if an exception be raised. */ * the handler if an exception be raised. */
return jump ? 3 : 0; return jump ? 1 : 0;
case SETUP_CLEANUP: case SETUP_CLEANUP:
/* As SETUP_FINALLY, but pushes lasti as well */ /* As SETUP_FINALLY, but pushes lasti as well */
return jump ? 4 : 0; return jump ? 2 : 0;
case SETUP_WITH: case SETUP_WITH:
/* 0 in the normal flow. /* 0 in the normal flow.
* Restore the stack position to the position before the result * Restore the stack position to the position before the result
* of __(a)enter__ and push 4 values before jumping to the handler * of __(a)enter__ and push 2 values before jumping to the handler
* if an exception be raised. */ * if an exception be raised. */
return jump ? -1 + 4 : 0; return jump ? 1 : 0;
case PREP_RERAISE_STAR: case PREP_RERAISE_STAR:
return 2; return 0;
case RERAISE: case RERAISE:
return -3; return -1;
case PUSH_EXC_INFO: case PUSH_EXC_INFO:
return 3; return 1;
case WITH_EXCEPT_START: case WITH_EXCEPT_START:
return 1; return 1;
@ -1199,7 +1199,7 @@ stack_effect(int opcode, int oparg, int jump)
case GET_YIELD_FROM_ITER: case GET_YIELD_FROM_ITER:
return 0; return 0;
case END_ASYNC_FOR: case END_ASYNC_FOR:
return -4; return -2;
case FORMAT_VALUE: case FORMAT_VALUE:
/* If there's a fmt_spec on the stack, we go from 2->1, /* If there's a fmt_spec on the stack, we go from 2->1,
else 1->1. */ else 1->1. */
@ -1888,13 +1888,11 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
case FINALLY_END: case FINALLY_END:
if (preserve_tos) { if (preserve_tos) {
ADDOP(c, ROT_FOUR); ADDOP(c, ROT_TWO);
} }
ADDOP(c, POP_TOP); ADDOP(c, POP_TOP); /* exc_value */
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
if (preserve_tos) { if (preserve_tos) {
ADDOP(c, ROT_FOUR); ADDOP(c, ROT_TWO);
} }
ADDOP(c, POP_BLOCK); ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT); ADDOP(c, POP_EXCEPT);
@ -1927,7 +1925,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
ADDOP(c, POP_BLOCK); ADDOP(c, POP_BLOCK);
} }
if (preserve_tos) { if (preserve_tos) {
ADDOP(c, ROT_FOUR); ADDOP(c, ROT_TWO);
} }
ADDOP(c, POP_BLOCK); ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT); ADDOP(c, POP_EXCEPT);
@ -3310,18 +3308,16 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s)
[] POP_BLOCK [] POP_BLOCK
[] JUMP_FORWARD L0 [] JUMP_FORWARD L0
[tb, val, exc] L1: <evaluate E1> ) [exc] L1: <evaluate E1> )
[tb, val, exc, E1] JUMP_IF_NOT_EXC_MATCH L2 ) only if E1 [exc, E1] JUMP_IF_NOT_EXC_MATCH L2 ) only if E1
[tb, val, exc] POP [exc] <assign to V1> (or POP if no V1)
[tb, val] <assign to V1> (or POP if no V1)
[tb] POP
[] <code for S1> [] <code for S1>
JUMP_FORWARD L0 JUMP_FORWARD L0
[tb, val, exc] L2: <evaluate E2> [exc] L2: <evaluate E2>
.............................etc....................... .............................etc.......................
[tb, val, exc] Ln+1: RERAISE # re-raise exception [exc] Ln+1: RERAISE # re-raise exception
[] L0: <next statement> [] L0: <next statement>
@ -3372,7 +3368,6 @@ compiler_try_except(struct compiler *c, stmt_ty s)
ADDOP_JUMP(c, JUMP_IF_NOT_EXC_MATCH, except); ADDOP_JUMP(c, JUMP_IF_NOT_EXC_MATCH, except);
NEXT_BLOCK(c); NEXT_BLOCK(c);
} }
ADDOP(c, POP_TOP);
if (handler->v.ExceptHandler.name) { if (handler->v.ExceptHandler.name) {
basicblock *cleanup_end, *cleanup_body; basicblock *cleanup_end, *cleanup_body;
@ -3383,7 +3378,6 @@ compiler_try_except(struct compiler *c, stmt_ty s)
} }
compiler_nameop(c, handler->v.ExceptHandler.name, Store); compiler_nameop(c, handler->v.ExceptHandler.name, Store);
ADDOP(c, POP_TOP);
/* /*
try: try:
@ -3434,8 +3428,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
if (!cleanup_body) if (!cleanup_body)
return 0; return 0;
ADDOP(c, POP_TOP); ADDOP(c, POP_TOP); /* exc_value */
ADDOP(c, POP_TOP);
compiler_use_next_block(c, cleanup_body); compiler_use_next_block(c, cleanup_body);
if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NULL, NULL)) if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NULL, NULL))
return 0; return 0;
@ -3467,52 +3460,42 @@ compiler_try_except(struct compiler *c, stmt_ty s)
at the right; 'tb' is trace-back info, 'val' the exception instance, at the right; 'tb' is trace-back info, 'val' the exception instance,
and 'typ' the exception's type.) and 'typ' the exception's type.)
Value stack Label Instruction Argument Value stack Label Instruction Argument
[] SETUP_FINALLY L1 [] SETUP_FINALLY L1
[] <code for S> [] <code for S>
[] POP_BLOCK [] POP_BLOCK
[] JUMP_FORWARD L0 [] JUMP_FORWARD L0
[tb, val, typ] L1: DUP_TOP_TWO ) save a copy of the [exc] L1: DUP_TOP ) save copy of the original exception
[tb, val, typ, orig, typ] POP_TOP ) original raised exception [orig, exc] BUILD_LIST ) list for raised/reraised excs ("result")
[tb, val, typ, orig] ROT_FOUR ) [orig, exc, res] ROT_TWO
[orig, tb, val, typ] BUILD_LIST ) list for raised/reraised
[orig, tb, val, typ, res] ROT_FOUR ) exceptions ("result")
[orig, res, tb, val, typ] <evaluate E1> ) [orig, res, exc] <evaluate E1>
[orig, res, tb, val, typ, E1] JUMP_IF_NOT_EXC_MATCH L2 ) only if E1 [orig, res, exc, E1] JUMP_IF_NOT_EG_MATCH L2
[orig, res, tb, rest, typ, tb, match, typ] POP [orig, res, rest, match] <assign to V1> (or POP if no V1)
[orig, res, tb, rest, typ, tb, match] <assign to V1> (or POP if no V1)
[orig, res, tb, rest, typ, tb] POP
[orig, res, tb, rest, typ] SETUP_FINALLY R1 [orig, res, rest] SETUP_FINALLY R1
[orig, res, tb, rest, typ] <code for S1> [orig, res, rest] <code for S1>
[orig, res, tb, rest, typ] JUMP_FORWARD L2 [orig, res, rest] JUMP_FORWARD L2
[orig, res, tb, rest, typ, i, tb, v, t] R1: POP ) exception raised in except* body [orig, res, rest, i, v] R1: LIST_APPEND 3 ) exc raised in except* body - add to res
[orig, res, tb, rest, typ, i, tb, v] LIST_APPEND 6 ) add it to res [orig, res, rest, i] POP
[orig, res, tb, rest, typ, i, tb] POP
[orig, res, tb, rest, typ, i] POP
[orig, res, tb, rest, typ] L2: <evaluate E2> [orig, res, rest] L2: <evaluate E2>
.............................etc....................... .............................etc.......................
[orig, res, tb, rest, typ] Ln+1: POP ) add unhandled exception [orig, res, rest] Ln+1: LIST_APPEND 1 ) add unhandled exc to res (could be None)
[orig, res, tb, rest] LIST_APPEND 2 ) to res (could be None)
[orig, res, tb] POP
[orig, res] PREP_RERAISE_STAR [orig, res] PREP_RERAISE_STAR
[i, tb, val, typ] POP_JUMP_IF_TRUE RER [i, exc] POP_JUMP_IF_TRUE RER
[i, tb, val, typ] POP [i, exc] POP
[i, tb, val] POP [i] POP
[i, tb] POP [] JUMP_FORWARD L0
[i] POP
[] JUMP_FORWARD L0
[i, tb, val, typ] RER: POP_EXCEPT_AND_RERAISE [i, exc] RER: POP_EXCEPT_AND_RERAISE
[] L0: <next statement> [] L0: <next statement>
*/ */
static int static int
compiler_try_star_except(struct compiler *c, stmt_ty s) compiler_try_star_except(struct compiler *c, stmt_ty s)
@ -3573,30 +3556,25 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
if (i == 0) { if (i == 0) {
/* Push the original EG into the stack */ /* Push the original EG into the stack */
/* /*
[tb, val, exc] DUP_TOP_TWO [exc] DUP_TOP
[tb, val, exc, val, exc] POP_TOP [orig, exc]
[tb, val, exc, val] ROT_FOUR
[val, tb, val, exc]
*/ */
ADDOP(c, DUP_TOP_TWO); ADDOP(c, DUP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, ROT_FOUR);
/* create empty list for exceptions raised/reraise in the except* blocks */ /* create empty list for exceptions raised/reraise in the except* blocks */
/* /*
[val, tb, val, exc] BUILD_LIST [orig, exc] BUILD_LIST
[val, tb, val, exc, []] ROT_FOUR [orig, exc, []] ROT_TWO
[val, [], tb, val, exc] [orig, [], exc]
*/ */
ADDOP_I(c, BUILD_LIST, 0); ADDOP_I(c, BUILD_LIST, 0);
ADDOP(c, ROT_FOUR); ADDOP(c, ROT_TWO);
} }
if (handler->v.ExceptHandler.type) { if (handler->v.ExceptHandler.type) {
VISIT(c, expr, handler->v.ExceptHandler.type); VISIT(c, expr, handler->v.ExceptHandler.type);
ADDOP_JUMP(c, JUMP_IF_NOT_EG_MATCH, except); ADDOP_JUMP(c, JUMP_IF_NOT_EG_MATCH, except);
NEXT_BLOCK(c); NEXT_BLOCK(c);
} }
ADDOP(c, POP_TOP); // exc_type
basicblock *cleanup_end = compiler_new_block(c); basicblock *cleanup_end = compiler_new_block(c);
if (cleanup_end == NULL) { if (cleanup_end == NULL) {
@ -3611,9 +3589,8 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
compiler_nameop(c, handler->v.ExceptHandler.name, Store); compiler_nameop(c, handler->v.ExceptHandler.name, Store);
} }
else { else {
ADDOP(c, POP_TOP); // val ADDOP(c, POP_TOP); // exc
} }
ADDOP(c, POP_TOP); // tb
/* /*
try: try:
@ -3657,9 +3634,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
} }
/* add exception raised to the res list */ /* add exception raised to the res list */
ADDOP(c, POP_TOP); // type ADDOP_I(c, LIST_APPEND, 3); // exc
ADDOP_I(c, LIST_APPEND, 6); // exc
ADDOP(c, POP_TOP); // tb
ADDOP(c, POP_TOP); // lasti ADDOP(c, POP_TOP); // lasti
ADDOP_JUMP(c, JUMP_ABSOLUTE, except); ADDOP_JUMP(c, JUMP_ABSOLUTE, except);
@ -3667,9 +3642,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
if (i == n - 1) { if (i == n - 1) {
/* Add exc to the list (if not None it's the unhandled part of the EG) */ /* Add exc to the list (if not None it's the unhandled part of the EG) */
ADDOP(c, POP_TOP); ADDOP_I(c, LIST_APPEND, 1);
ADDOP_I(c, LIST_APPEND, 2);
ADDOP(c, POP_TOP);
ADDOP_JUMP(c, JUMP_FORWARD, reraise_star); ADDOP_JUMP(c, JUMP_FORWARD, reraise_star);
} }
} }
@ -3690,8 +3663,6 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
/* Nothing to reraise - pop it */ /* Nothing to reraise - pop it */
ADDOP(c, POP_TOP); ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP); ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_BLOCK); ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT); ADDOP(c, POP_EXCEPT);
ADDOP_JUMP(c, JUMP_FORWARD, end); ADDOP_JUMP(c, JUMP_FORWARD, end);
@ -5449,13 +5420,11 @@ compiler_with_except_finish(struct compiler *c, basicblock * cleanup) {
return 0; return 0;
ADDOP_JUMP(c, POP_JUMP_IF_TRUE, exit); ADDOP_JUMP(c, POP_JUMP_IF_TRUE, exit);
NEXT_BLOCK(c); NEXT_BLOCK(c);
ADDOP_I(c, RERAISE, 4); ADDOP_I(c, RERAISE, 2);
compiler_use_next_block(c, cleanup); compiler_use_next_block(c, cleanup);
ADDOP(c, POP_EXCEPT_AND_RERAISE); ADDOP(c, POP_EXCEPT_AND_RERAISE);
compiler_use_next_block(c, exit); compiler_use_next_block(c, exit);
ADDOP(c, POP_TOP); ADDOP(c, POP_TOP); /* exc_value */
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_BLOCK); ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT); ADDOP(c, POP_EXCEPT);
ADDOP(c, POP_TOP); ADDOP(c, POP_TOP);
@ -5587,7 +5556,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
E: WITH_EXCEPT_START (calls EXPR.__exit__) E: WITH_EXCEPT_START (calls EXPR.__exit__)
POP_JUMP_IF_TRUE T: POP_JUMP_IF_TRUE T:
RERAISE RERAISE
T: POP_TOP * 3 (remove exception from stack) T: POP_TOP (remove exception from stack)
POP_EXCEPT POP_EXCEPT
POP_TOP POP_TOP
EXIT: EXIT:
@ -7368,7 +7337,10 @@ assemble_emit_exception_table_entry(struct assembler *a, int start, int end, bas
int size = end-start; int size = end-start;
assert(end > start); assert(end > start);
int target = handler->b_offset; int target = handler->b_offset;
int depth = handler->b_preserve_lasti ? handler->b_startdepth-4 : handler->b_startdepth-3; int depth = handler->b_startdepth - 1;
if (handler->b_preserve_lasti) {
depth -= 1;
}
assert(depth >= 0); assert(depth >= 0);
int depth_lasti = (depth<<1) | handler->b_preserve_lasti; int depth_lasti = (depth<<1) | handler->b_preserve_lasti;
assemble_emit_exception_table_item(a, start, (1<<7)); assemble_emit_exception_table_item(a, start, (1<<7));

View File

@ -84,11 +84,8 @@ _PyErr_GetTopmostException(PyThreadState *tstate)
while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) && while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) &&
exc_info->previous_item != NULL) exc_info->previous_item != NULL)
{ {
assert(exc_info->exc_type == NULL || exc_info->exc_type == Py_None);
exc_info = exc_info->previous_item; exc_info = exc_info->previous_item;
} }
assert(exc_info->previous_item == NULL ||
(exc_info->exc_type != NULL && exc_info->exc_type != Py_None));
return exc_info; return exc_info;
} }
@ -524,27 +521,17 @@ PyErr_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback)
void void
PyErr_SetExcInfo(PyObject *type, PyObject *value, PyObject *traceback) PyErr_SetExcInfo(PyObject *type, PyObject *value, PyObject *traceback)
{ {
PyObject *oldtype, *oldvalue, *oldtraceback;
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyThreadState_GET();
oldtype = tstate->exc_info->exc_type; PyObject *oldvalue = tstate->exc_info->exc_value;
oldvalue = tstate->exc_info->exc_value;
oldtraceback = tstate->exc_info->exc_traceback;
tstate->exc_info->exc_type = get_exc_type(value);
Py_XINCREF(tstate->exc_info->exc_type);
tstate->exc_info->exc_value = value; tstate->exc_info->exc_value = value;
tstate->exc_info->exc_traceback = get_exc_traceback(value);
Py_XINCREF(tstate->exc_info->exc_traceback);
/* These args are no longer used, but we still need to steal a ref */ /* These args are no longer used, but we still need to steal a ref */
Py_XDECREF(type); Py_XDECREF(type);
Py_XDECREF(traceback); Py_XDECREF(traceback);
Py_XDECREF(oldtype);
Py_XDECREF(oldvalue); Py_XDECREF(oldvalue);
Py_XDECREF(oldtraceback);
} }
@ -629,9 +616,6 @@ _PyErr_ChainStackItem(_PyErr_StackItem *exc_info)
exc_info_given = 1; exc_info_given = 1;
} }
assert( (exc_info->exc_type == NULL || exc_info->exc_type == Py_None) ==
(exc_info->exc_value == NULL || exc_info->exc_value == Py_None) );
if (exc_info->exc_value == NULL || exc_info->exc_value == Py_None) { if (exc_info->exc_value == NULL || exc_info->exc_value == Py_None) {
return; return;
} }

View File

@ -1028,9 +1028,7 @@ PyThreadState_Clear(PyThreadState *tstate)
Py_CLEAR(tstate->curexc_value); Py_CLEAR(tstate->curexc_value);
Py_CLEAR(tstate->curexc_traceback); Py_CLEAR(tstate->curexc_traceback);
Py_CLEAR(tstate->exc_state.exc_type);
Py_CLEAR(tstate->exc_state.exc_value); Py_CLEAR(tstate->exc_state.exc_value);
Py_CLEAR(tstate->exc_state.exc_traceback);
/* The stack of exception states should contain just this thread. */ /* The stack of exception states should contain just this thread. */
if (verbose && tstate->exc_info != &tstate->exc_state) { if (verbose && tstate->exc_info != &tstate->exc_state) {