8000 GH-94438: Handle extended arguments and conditional pops in mark_stac… · python/cpython@e4d3a96 · GitHub
[go: up one dir, main page]

Skip to content

Commit e4d3a96

Browse files
authored
GH-94438: Handle extended arguments and conditional pops in mark_stacks (GH-95110)
1 parent 900bfc5 commit e4d3a96

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

Lib/test/test_sys_settrace.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2685,6 +2685,42 @@ def test_jump_with_null_on_stack_load_attr(output):
26852685
)
26862686
output.append(15)
26872687

2688+
@jump_test(2, 3, [1, 3])
2689+
def test_jump_extended_args_unpack_ex_simple(output):
2690+
output.append(1)
2691+
_, *_, _ = output.append(2) or "Spam"
2692+
output.append(3)
2693+
2694+
@jump_test(3, 4, [1, 4, 4, 5])
2695+
def test_jump_extended_args_unpack_ex_tricky(output):
2696+
output.append(1)
2697+
(
2698+
_, *_, _
2699+
) = output.append(4) or "Spam"
2700+
output.append(5)
2701+
2702+
def test_jump_extended_args_for_iter(self):
2703+
# In addition to failing when extended arg handling is broken, this can
2704+
# also hang for a *very* long time:
2705+
source = [
2706+
"def f(output):",
2707+
" output.append(1)",
2708+
" for _ in spam:",
2709+
*(f" output.append({i})" for i in range(3, 100_000)),
2710+
f" output.append(100_000)",
2711+
]
2712+
namespace = {}
2713+
exec("\n".join(source), namespace)
2714+
f = namespace["f"]
2715+
self.run_test(f, 2, 100_000, [1, 100_000])
2716+
2717+
@jump_test(2, 3, [1, 3])
2718+
def test_jump_or_pop(output):
2719+
output.append(1)
2720+
_ = output.append(2) and "Spam"
2721+
output.append(3)
2722+
2723+
26882724
class TestExtendedArgs(unittest.TestCase):
26892725

26902726
def setUp(self):
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fix an issue that caused extended opcode arguments and some conditional pops
2+
to be ignored when calculating valid jump targets for assignments to the
3+
``f_lineno`` attribute of frame objects. In some cases, this could cause
4+
inconsistent internal state, resulting in a hard crash of the interpreter.

Objects/frameobject.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,11 +319,15 @@ mark_stacks(PyCodeObject *code_obj, int len)
319319
int64_t target_stack;
320320
int j = get_arg(code, i);
321321
if (opcode == POP_JUMP_FORWARD_IF_FALSE ||
322-
opcode == POP_JUMP_FORWARD_IF_TRUE) {
322+
opcode == POP_JUMP_FORWARD_IF_TRUE ||
323+
opcode == JUMP_IF_FALSE_OR_POP ||
324+
opcode == JUMP_IF_TRUE_OR_POP)
325+
{
323326
j += i + 1;
324327
}
325-
else if (opcode == POP_JUMP_BACKWARD_IF_FALSE ||
326-
opcode == POP_JUMP_BACKWARD_IF_TRUE) {
328+
else {
329+
assert(opcode == POP_JUMP_BACKWARD_IF_FALSE ||
330+
opcode == POP_JUMP_BACKWARD_IF_TRUE);
327331
j = i + 1 - j;
328332
}
329333
assert(j < len);
@@ -459,7 +463,8 @@ mark_stacks(PyCodeObject *code_obj, int len)
459463
}
460464
default:
461465
{
462-
int delta = PyCompile_OpcodeStackEffect(opcode, _Py_OPARG(code[i]));
466+
int delta = PyCompile_OpcodeStackEffect(opcode, get_arg(code, i));
467+
assert(delta != PY_INVALID_STACK_EFFECT);
463468
while (delta < 0) {
464469
next_stack = pop_value(next_stack);
465470
delta++;

0 commit comments

Comments
 (0)
0