Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bf353f3

Browse files
authored
bpo-42246: Make sure that f_lasti, and thus f_lineno, is set correctly after raising or reraising an exception (GH-23803)
* Ensure that f_lasti is set correctly after an exception is raised to conform to PEP 626. * Update importlib * Add NEWS.
1 parent 40125ab commit bf353f3

File tree

13 files changed

+317
-225
lines changed

13 files changed

+317
-225
lines changed

Doc/library/dis.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,8 @@ iterations of the loop.
708708

709709
.. opcode:: RERAISE
710710

711-
Re-raises the exception currently on top of the stack.
711+
Re-raises the exception currently on top of the stack. If oparg is non-zero,
712+
restores ``f_lasti`` of the current frame to its value when the exception was raised.
712713

713714
.. versionadded:: 3.9
714715

Include/opcode.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/importlib/_bootstrap_external.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ def _write_atomic(path, data, mode=0o666):
312312
# Python 3.10a1 3430 (Make 'annotations' future by default)
313313
# Python 3.10a1 3431 (New line number table format -- PEP 626)
314314
# Python 3.10a2 3432 (Function annotation for MAKE_FUNCTION is changed from dict to tuple bpo-42202)
315+
# Python 3.10a2 3433 (RERAISE restores f_lasti if oparg != 0)
315316

316317
#
317318
# MAGIC must change whenever the bytecode emitted by the compiler may no
@@ -321,7 +322,7 @@ def _write_atomic(path, data, mode=0o666):
321322
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
322323
# in PC/launcher.c must also be updated.
323324

324-
MAGIC_NUMBER = (3432).to_bytes(2, 'little') + b'\r\n'
325+
MAGIC_NUMBER = (3433).to_bytes(2, 'little') + b'\r\n'
325326
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
326327

327328
_PYCACHE = '__pycache__'

Lib/opcode.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ def jabs_op(name, op):
8383
def_op('INPLACE_FLOOR_DIVIDE', 28)
8484
def_op('INPLACE_TRUE_DIVIDE', 29)
8585

86-
def_op('RERAISE', 48)
8786
def_op('WITH_EXCEPT_START', 49)
8887
def_op('GET_AITER', 50)
8988
def_op('GET_ANEXT', 51)
@@ -161,6 +160,7 @@ def jabs_op(name, op):
161160

162161
def_op('IS_OP', 117)
163162
def_op('CONTAINS_OP', 118)
163+
def_op('RERAISE', 119)
164164

165165
jabs_op('JUMP_IF_NOT_EXC_MATCH', 121)
166166
jrel_op('SETUP_FINALLY', 122) # Distance to target address

Lib/test/test_dis.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -313,9 +313,9 @@ def bug42562():
313313
>> 50 LOAD_CONST 0 (None)
314314
52 STORE_FAST 0 (e)
315315
54 DELETE_FAST 0 (e)
316-
56 RERAISE
316+
56 RERAISE 1
317317
318-
%3d >> 58 RERAISE
318+
%3d >> 58 RERAISE 0
319319
""" % (TRACEBACK_CODE.co_firstlineno + 1,
320320
TRACEBACK_CODE.co_firstlineno + 2,
321321
TRACEBACK_CODE.co_firstlineno + 5,
@@ -370,7 +370,7 @@ def _tryfinallyconst(b):
370370
>> 14 LOAD_FAST 1 (b)
371371
16 CALL_FUNCTION 0
372372
18 POP_TOP
373-
20 RERAISE
373+
20 RERAISE 0
374374
""" % (_tryfinally.__code__.co_firstlineno + 1,
375375
_tryfinally.__code__.co_firstlineno + 2,
376376
_tryfinally.__code__.co_firstlineno + 4,
@@ -389,7 +389,7 @@ def _tryfinallyconst(b):
389389
>> 14 LOAD_FAST 0 (b)
390390
16 CALL_FUNCTION 0
391391
18 POP_TOP
392-
20 RERAISE
392+
20 RERAISE 0
393393
""" % (_tryfinallyconst.__code__.co_firstlineno + 1,
394394
_tryfinallyconst.__code__.co_firstlineno + 2,
395395
_tryfinallyconst.__code__.co_firstlineno + 4,
@@ -1076,7 +1076,7 @@ def jumpy():
10761076
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=136, starts_line=None, is_jump_target=False),
10771077
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=138, starts_line=None, is_jump_target=False),
10781078
Instruction(opname='JUMP_FORWARD', opcode=110, arg=46, argval=188, argrepr='to 188', offset=140, starts_line=None, is_jump_target=False),
1079-
Instruction(opname='RERAISE', opcode=48, arg=None, argval=None, argrepr='', offset=142, starts_line=None, is_jump_target=True),
1079+
Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=142, starts_line=None, is_jump_target=True),
10801080
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=144, starts_line=25, is_jump_target=True),
10811081
Instruction(opname='SETUP_WITH', opcode=143, arg=24, argval=172, argrepr='to 172', offset=146, starts_line=None, is_jump_target=False),
10821082
Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=148, starts_line=None, is_jump_target=False),
@@ -1093,7 +1093,7 @@ def jumpy():
10931093
Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=188, argrepr='to 188', offset=170, starts_line=None, is_jump_target=False),
10941094
Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=True),
10951095
Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=178, argval=178, argrepr='', offset=174, starts_line=None, is_jump_target=False),
1096-
Instruction(opname='RERAISE', opcode=48, arg=None, argval=None, argrepr='', offset=176, starts_line=None, is_jump_target=False),
1096+
Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=176, starts_line=None, is_jump_target=False),
10971097
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=178, starts_line=None, is_jump_target=True),
10981098
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=180, starts_line=None, is_jump_target=False),
10991099
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=182, starts_line=None, is_jump_target=False),
@@ -1110,7 +1110,7 @@ def jumpy():
11101110
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=204, starts_line=None, is_jump_target=False),
11111111
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=206, starts_line=None, is_jump_target=False),
11121112
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=208, starts_line=None, is_jump_target=False),
1113-
Instruction(opname='RERAISE', opcode=48, arg=None, argval=None, argrepr='', offset=210, starts_line=None, is_jump_target=False),
1113+
Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=210, starts_line=None, is_jump_target=False),
11141114
]
11151115

11161116
# One last piece of inspect fodder to check the default line number handling

Lib/test/test_exceptions.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,5 +1488,88 @@ def test_copy_pickle(self):
14881488
self.assertEqual(exc.path, orig.path)
14891489

14901490

1491+
class PEP626Tests(unittest.TestCase):
1492+
1493+
def lineno_after_raise(self, f, line):
1494+
try:
1495+
f()
1496+
except Exception as ex:
1497+
t = ex.__traceback__
1498+
while t.tb_next:
1499+
t = t.tb_next
1500+
frame = t.tb_frame
1501+
self.assertEqual(frame.f_lineno-frame.f_code.co_firstlineno, line)
1502+
1503+
def test_lineno_after_raise_simple(self):
1504+
def simple():
1505+
1/0
1506+
pass
1507+
self.lineno_after_raise(simple, 1)
1508+
1509+
def test_lineno_after_raise_in_except(self):
1510+
def in_except():
1511+
try:
1512+
1/0
1513+
except:
1514+
1/0
1515+
pass
1516+
self.lineno_after_raise(in_except, 4)
1517+
1518+
def test_lineno_after_other_except(self):
1519+
def other_except():
1520+
try:
1521+
1/0
1522+
except TypeError as ex:
1523+
pass
1524+
self.lineno_after_raise(other_except, 3)
1525+
1526+
def test_lineno_in_named_except(self):
1527+
def in_named_except():
1528+
try:
1529+
1/0
1530+
except Exception as ex:
1531+
1/0
1532+
pass
1533+
self.lineno_after_raise(in_named_except, 4)
1534+
1535+
def test_lineno_in_try(self):
1536+
def in_try():
1537+
try:
1538+
1/0
1539+
finally:
1540+
pass
1541+
self.lineno_after_raise(in_try, 4)
1542+
1543+
def test_lineno_in_finally_normal(self):
1544+
def in_finally_normal():
1545+
try:
1546+
pass
1547+
finally:
1548+
1/0
1549+
pass
1550+
self.lineno_after_raise(in_finally_normal, 4)
1551+
1552+
def test_lineno_in_finally_except(self):
1553+
def in_finally_except():
1554+
try:
1555+
1/0
1556+
finally:
1557+
1/0
1558+
pass
1559+
self.lineno_after_raise(in_finally_except, 4)
1560+
1561+
def test_lineno_after_with(self):
1562+
class Noop:
1563+
def __enter__(self):
1564+
return self
1565+
def __exit__(self, *args):
1566+
pass
1567+
def after_with():
1568+
with Noop():
1569+
1/0
1570+
pass
1571+
self.lineno_after_raise(after_with, 2)
1572+
1573+
14911574
if __name__ == '__main__':
14921575
unittest.main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Make sure that the ``f_lasti`` and ``f_lineno`` attributes of a frame are
2+
set correctly when an exception is raised or re-raised. Required for PEP
3+
626.

Python/ceval.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2430,6 +2430,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
24302430
}
24312431

24322432
case TARGET(RERAISE): {
2433+
assert(f->f_iblock > 0);
2434+
if (oparg) {
2435+
f->f_lasti = f->f_blockstack[f->f_iblock-1].b_handler;
2436+
}
24332437
PyObject *exc = POP();
24342438
PyObject *val = POP();
24352439
PyObject *tb = POP();
@@ -4039,7 +4043,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
40394043
int handler = b->b_handler;
40404044
_PyErr_StackItem *exc_info = tstate->exc_info;
40414045
/* Beware, this invalidates all b->b_* fields */
4042-
PyFrame_BlockSetup(f, EXCEPT_HANDLER, -1, STACK_LEVEL());
4046+
PyFrame_BlockSetup(f, EXCEPT_HANDLER, f->f_lasti, STACK_LEVEL());
40434047
PUSH(exc_info->exc_traceback);
40444048
PUSH(exc_info->exc_value);
40454049
if (exc_info->exc_type != NULL) {

Python/compile.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2981,7 +2981,7 @@ compiler_try_finally(struct compiler *c, stmt_ty s)
29812981
return 0;
29822982
VISIT_SEQ(c, stmt, s->v.Try.finalbody);
29832983
compiler_pop_fblock(c, FINALLY_END, end);
2984-
ADDOP(c, RERAISE);
2984+
ADDOP_I(c, RERAISE, 0);
29852985
compiler_use_next_block(c, exit);
29862986
return 1;
29872987
}
@@ -3107,7 +3107,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
31073107
compiler_nameop(c, handler->v.ExceptHandler.name, Store);
31083108
compiler_nameop(c, handler->v.ExceptHandler.name, Del);
31093109

3110-
ADDOP(c, RERAISE);
3110+
ADDOP_I(c, RERAISE, 1);
31113111
}
31123112
else {
31133113
basicblock *cleanup_body;
@@ -3129,7 +3129,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
31293129
compiler_use_next_block(c, except);
31303130
}
31313131
compiler_pop_fblock(c, EXCEPTION_HANDLER, NULL);
3132-
ADDOP(c, RERAISE);
3132+
ADDOP_I(c, RERAISE, 0);
31333133
compiler_use_next_block(c, orelse);
31343134
VISIT_SEQ(c, stmt, s->v.Try.orelse);
31353135
compiler_use_next_block(c, end);
@@ -4759,7 +4759,7 @@ compiler_with_except_finish(struct compiler *c) {
47594759
return 0;
47604760
ADDOP_JUMP(c, POP_JUMP_IF_TRUE, exit);
47614761
NEXT_BLOCK(c);
4762-
ADDOP(c, RERAISE);
4762+
ADDOP_I(c, RERAISE, 1);
47634763
compiler_use_next_block(c, exit);
47644764
ADDOP(c, POP_TOP);
47654765
ADDOP(c, POP_TOP);

0 commit comments

Comments
 (0)