Skip to content

Commit

Permalink
bpo-45711: Remove type and traceback from exc_info (GH-30122)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
iritkatriel authored Dec 17, 2021
1 parent 62a0a2a commit 396b583
Show file tree
Hide file tree
Showing 14 changed files with 231 additions and 392 deletions.
34 changes: 21 additions & 13 deletions Doc/library/dis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -474,13 +474,15 @@ the original TOS1.
.. opcode:: END_ASYNC_FOR

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
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.

.. versionadded:: 3.8

.. versionchanged:: 3.11
Exception representation on the stack now consist of one, not three, items.

.. opcode:: BEFORE_ASYNC_WITH

Expand Down Expand Up @@ -561,8 +563,10 @@ iterations of the loop.

.. 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

Expand All @@ -572,27 +576,32 @@ iterations of the loop.

.. versionadded:: 3.9

.. versionchanged:: 3.11
Exception representation on the stack now consist of one, not three, items.

.. opcode:: PUSH_EXC_INFO

Pops the three values from the stack. Pushes the current exception to the top of the stack.
Pushes the three values originally popped back to the stack.
Pops a value from the stack. Pushes the current exception to the top of the stack.
Pushes the value originally popped back to the stack.
Used in exception handlers.

.. versionadded:: 3.11


.. opcode:: WITH_EXCEPT_START

Calls the function in position 8 on the stack with the top three
items on the stack as arguments.
Calls the function in position 4 on the stack with arguments (type, val, tb)
representing the exception at the top of the stack.
Used to implement the call ``context_manager.__exit__(*exc_info())`` when an exception
has occurred in a :keyword:`with` statement.

.. versionadded:: 3.9
.. versionchanged:: 3.11
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

Expand Down Expand Up @@ -890,10 +899,9 @@ All of the following opcodes use their arguments.
Performs exception matching for ``except*``. Applies ``split(TOS)`` on
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
the exception and pushes the 3 items representing the non-matching part of
the exception group, followed by the 3 items representing the matching part.
In other words, in case of a match it pops 4 items and pushes 6.
Pops one item from the stack (the match type). If a match was found,
next item (the exception) and pushes the non-matching part of the
exception group followed by the matching part.

.. versionadded:: 3.11

Expand All @@ -903,8 +911,8 @@ All of the following opcodes use their arguments.
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 from TOS1 to reconstruct the structure of reraised exceptions. Pops
two items from the stack and pushes a triplet representing the exception to
reraise or three ``None`` if there isn't one.
two items from the stack and pushes 0 (for lasti, which is unused) followed
by the exception to reraise or ``None`` if there isn't one.

.. versionadded:: 3.11

Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.11.rst
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ Other CPython Implementation Changes
reflected in the re-raised exception.
(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
===========

Expand Down
2 changes: 1 addition & 1 deletion Include/cpython/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ typedef struct _err_stackitem {
* This ensures that the exception state is not impacted by "yields"
* from an except handler.
*/
PyObject *exc_type, *exc_value, *exc_traceback;
PyObject *exc_value;

struct _err_stackitem *previous_item;

Expand Down
12 changes: 2 additions & 10 deletions Include/internal/pycore_pyerrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,7 @@ static inline PyObject* _PyErr_Occurred(PyThreadState *tstate)

static inline void _PyErr_ClearExcState(_PyErr_StackItem *exc_state)
{
PyObject *t, *v, *tb;
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);
Py_CLEAR(exc_state->exc_value);
}

PyAPI_FUNC(PyObject*) _PyErr_StackItemToExcInfoTuple(
Expand Down Expand Up @@ -114,6 +105,7 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc(

#define _Py_FatalRefcountError(message) _Py_FatalRefcountErrorFunc(__func__, message)


#ifdef __cplusplus
}
#endif
Expand Down
5 changes: 3 additions & 2 deletions Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,10 @@ def _write_atomic(path, data, mode=0o666):
# Python 3.11a3 3464 (bpo-45636: Merge numeric BINARY_*/INPLACE_* into
# BINARY_OP)
# 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 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
Expand All @@ -383,7 +384,7 @@ def _write_atomic(path, data, mode=0o666):
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# 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

_PYCACHE = '__pycache__'
Expand Down
Loading

0 comments on commit 396b583

Please sign in to comment.