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

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

View file

@ -1048,9 +1048,9 @@ stack_effect(int opcode, int oparg, int jump)
case POP_BLOCK:
return 0;
case POP_EXCEPT:
return -3;
return -1;
case POP_EXCEPT_AND_RERAISE:
return -7;
return -3;
case STORE_NAME:
return -1;
@ -1095,7 +1095,7 @@ stack_effect(int opcode, int oparg, int jump)
case JUMP_IF_NOT_EXC_MATCH:
return -1;
case JUMP_IF_NOT_EG_MATCH:
return jump > 0 ? -1 : 2;
return jump > 0 ? -1 : 0;
case IMPORT_NAME:
return -1;
case IMPORT_FROM:
@ -1120,25 +1120,25 @@ stack_effect(int opcode, int oparg, int jump)
/* Exception handling pseudo-instructions */
case SETUP_FINALLY:
/* 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. */
return jump ? 3 : 0;
return jump ? 1 : 0;
case SETUP_CLEANUP:
/* As SETUP_FINALLY, but pushes lasti as well */
return jump ? 4 : 0;
return jump ? 2 : 0;
case SETUP_WITH:
/* 0 in the normal flow.
* 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. */
return jump ? -1 + 4 : 0;
return jump ? 1 : 0;
case PREP_RERAISE_STAR:
return 2;
return 0;
case RERAISE:
return -3;
return -1;
case PUSH_EXC_INFO:
return 3;
return 1;
case WITH_EXCEPT_START:
return 1;
@ -1199,7 +1199,7 @@ stack_effect(int opcode, int oparg, int jump)
case GET_YIELD_FROM_ITER:
return 0;
case END_ASYNC_FOR:
return -4;
return -2;
case FORMAT_VALUE:
/* If there's a fmt_spec on the stack, we go from 2->1,
else 1->1. */
@ -1888,13 +1888,11 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
case FINALLY_END:
if (preserve_tos) {
ADDOP(c, ROT_FOUR);
ADDOP(c, ROT_TWO);
}
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP); /* exc_value */
if (preserve_tos) {
ADDOP(c, ROT_FOUR);
ADDOP(c, ROT_TWO);
}
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
@ -1927,7 +1925,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
ADDOP(c, POP_BLOCK);
}
if (preserve_tos) {
ADDOP(c, ROT_FOUR);
ADDOP(c, ROT_TWO);
}
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
@ -3310,18 +3308,16 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s)
[] POP_BLOCK
[] JUMP_FORWARD L0
[tb, val, exc] L1: <evaluate E1> )
[tb, val, exc, E1] JUMP_IF_NOT_EXC_MATCH L2 ) only if E1
[tb, val, exc] POP
[tb, val] <assign to V1> (or POP if no V1)
[tb] POP
[exc] L1: <evaluate E1> )
[exc, E1] JUMP_IF_NOT_EXC_MATCH L2 ) only if E1
[exc] <assign to V1> (or POP if no V1)
[] <code for S1>
JUMP_FORWARD L0
[tb, val, exc] L2: <evaluate E2>
[exc] L2: <evaluate E2>
.............................etc.......................
[tb, val, exc] Ln+1: RERAISE # re-raise exception
[exc] Ln+1: RERAISE # re-raise exception
[] 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);
NEXT_BLOCK(c);
}
ADDOP(c, POP_TOP);
if (handler->v.ExceptHandler.name) {
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);
ADDOP(c, POP_TOP);
/*
try:
@ -3434,8 +3428,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
if (!cleanup_body)
return 0;
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP); /* exc_value */
compiler_use_next_block(c, cleanup_body);
if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NULL, NULL))
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,
and 'typ' the exception's type.)
Value stack Label Instruction Argument
[] SETUP_FINALLY L1
[] <code for S>
[] POP_BLOCK
[] JUMP_FORWARD L0
Value stack Label Instruction Argument
[] SETUP_FINALLY L1
[] <code for S>
[] POP_BLOCK
[] JUMP_FORWARD L0
[tb, val, typ] L1: DUP_TOP_TWO ) save a copy of the
[tb, val, typ, orig, typ] POP_TOP ) original raised exception
[tb, val, typ, orig] ROT_FOUR )
[orig, tb, val, typ] BUILD_LIST ) list for raised/reraised
[orig, tb, val, typ, res] ROT_FOUR ) exceptions ("result")
[exc] L1: DUP_TOP ) save copy of the original exception
[orig, exc] BUILD_LIST ) list for raised/reraised excs ("result")
[orig, exc, res] ROT_TWO
[orig, res, tb, val, typ] <evaluate E1> )
[orig, res, tb, val, typ, E1] JUMP_IF_NOT_EXC_MATCH L2 ) only if E1
[orig, res, exc] <evaluate E1>
[orig, res, exc, E1] JUMP_IF_NOT_EG_MATCH L2
[orig, res, tb, rest, typ, tb, match, typ] POP
[orig, res, tb, rest, typ, tb, match] <assign to V1> (or POP if no V1)
[orig, res, tb, rest, typ, tb] POP
[orig, res, rest, match] <assign to V1> (or POP if no V1)
[orig, res, tb, rest, typ] SETUP_FINALLY R1
[orig, res, tb, rest, typ] <code for S1>
[orig, res, tb, rest, typ] JUMP_FORWARD L2
[orig, res, rest] SETUP_FINALLY R1
[orig, res, rest] <code for S1>
[orig, res, rest] JUMP_FORWARD L2
[orig, res, tb, rest, typ, i, tb, v, t] R1: POP ) exception raised in except* body
[orig, res, tb, rest, typ, i, tb, v] LIST_APPEND 6 ) add it to res
[orig, res, tb, rest, typ, i, tb] POP
[orig, res, tb, rest, typ, i] POP
[orig, res, rest, i, v] R1: LIST_APPEND 3 ) exc raised in except* body - add to res
[orig, res, rest, i] POP
[orig, res, tb, rest, typ] L2: <evaluate E2>
[orig, res, rest] L2: <evaluate E2>
.............................etc.......................
[orig, res, tb, rest, typ] Ln+1: POP ) add unhandled exception
[orig, res, tb, rest] LIST_APPEND 2 ) to res (could be None)
[orig, res, tb] POP
[orig, res, rest] Ln+1: LIST_APPEND 1 ) add unhandled exc to res (could be None)
[orig, res] PREP_RERAISE_STAR
[i, tb, val, typ] POP_JUMP_IF_TRUE RER
[i, tb, val, typ] POP
[i, tb, val] POP
[i, tb] POP
[i] POP
[] JUMP_FORWARD L0
[orig, res] PREP_RERAISE_STAR
[i, exc] POP_JUMP_IF_TRUE RER
[i, exc] POP
[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
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) {
/* Push the original EG into the stack */
/*
[tb, val, exc] DUP_TOP_TWO
[tb, val, exc, val, exc] POP_TOP
[tb, val, exc, val] ROT_FOUR
[val, tb, val, exc]
[exc] DUP_TOP
[orig, exc]
*/
ADDOP(c, DUP_TOP_TWO);
ADDOP(c, POP_TOP);
ADDOP(c, ROT_FOUR);
ADDOP(c, DUP_TOP);
/* create empty list for exceptions raised/reraise in the except* blocks */
/*
[val, tb, val, exc] BUILD_LIST
[val, tb, val, exc, []] ROT_FOUR
[val, [], tb, val, exc]
[orig, exc] BUILD_LIST
[orig, exc, []] ROT_TWO
[orig, [], exc]
*/
ADDOP_I(c, BUILD_LIST, 0);
ADDOP(c, ROT_FOUR);
ADDOP(c, ROT_TWO);
}
if (handler->v.ExceptHandler.type) {
VISIT(c, expr, handler->v.ExceptHandler.type);
ADDOP_JUMP(c, JUMP_IF_NOT_EG_MATCH, except);
NEXT_BLOCK(c);
}
ADDOP(c, POP_TOP); // exc_type
basicblock *cleanup_end = compiler_new_block(c);
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);
}
else {
ADDOP(c, POP_TOP); // val
ADDOP(c, POP_TOP); // exc
}
ADDOP(c, POP_TOP); // tb
/*
try:
@ -3657,9 +3634,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
}
/* add exception raised to the res list */
ADDOP(c, POP_TOP); // type
ADDOP_I(c, LIST_APPEND, 6); // exc
ADDOP(c, POP_TOP); // tb
ADDOP_I(c, LIST_APPEND, 3); // exc
ADDOP(c, POP_TOP); // lasti
ADDOP_JUMP(c, JUMP_ABSOLUTE, except);
@ -3667,9 +3642,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
if (i == n - 1) {
/* 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, 2);
ADDOP(c, POP_TOP);
ADDOP_I(c, LIST_APPEND, 1);
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 */
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
ADDOP_JUMP(c, JUMP_FORWARD, end);
@ -5449,13 +5420,11 @@ compiler_with_except_finish(struct compiler *c, basicblock * cleanup) {
return 0;
ADDOP_JUMP(c, POP_JUMP_IF_TRUE, exit);
NEXT_BLOCK(c);
ADDOP_I(c, RERAISE, 4);
ADDOP_I(c, RERAISE, 2);
compiler_use_next_block(c, cleanup);
ADDOP(c, POP_EXCEPT_AND_RERAISE);
compiler_use_next_block(c, exit);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP); /* exc_value */
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
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__)
POP_JUMP_IF_TRUE T:
RERAISE
T: POP_TOP * 3 (remove exception from stack)
T: POP_TOP (remove exception from stack)
POP_EXCEPT
POP_TOP
EXIT:
@ -7368,7 +7337,10 @@ assemble_emit_exception_table_entry(struct assembler *a, int start, int end, bas
int size = end-start;
assert(end > start);
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);
int depth_lasti = (depth<<1) | handler->b_preserve_lasti;
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) &&
exc_info->previous_item != NULL)
{
assert(exc_info->exc_type == NULL || exc_info->exc_type == Py_None);
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;
}
@ -524,27 +521,17 @@ PyErr_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback)
void
PyErr_SetExcInfo(PyObject *type, PyObject *value, PyObject *traceback)
{
PyObject *oldtype, *oldvalue, *oldtraceback;
PyThreadState *tstate = _PyThreadState_GET();
oldtype = tstate->exc_info->exc_type;
oldvalue = tstate->exc_info->exc_value;
oldtraceback = tstate->exc_info->exc_traceback;
PyObject *oldvalue = tstate->exc_info->exc_value;
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_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 */
Py_XDECREF(type);
Py_XDECREF(traceback);
Py_XDECREF(oldtype);
Py_XDECREF(oldvalue);
Py_XDECREF(oldtraceback);
}
@ -629,9 +616,6 @@ _PyErr_ChainStackItem(_PyErr_StackItem *exc_info)
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) {
return;
}

View file

@ -1028,9 +1028,7 @@ PyThreadState_Clear(PyThreadState *tstate)
Py_CLEAR(tstate->curexc_value);
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_traceback);
/* The stack of exception states should contain just this thread. */
if (verbose && tstate->exc_info != &tstate->exc_state) {