Skip to content

Commit

Permalink
pythonGH-94438: Handle extended arguments and conditional pops in mar…
Browse files Browse the repository at this point in the history
…k_stacks (pythonGH-95110)
  • Loading branch information
brandtbucher authored Jul 22, 2022
1 parent 900bfc5 commit e4d3a96
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 4 deletions.
36 changes: 36 additions & 0 deletions Lib/test/test_sys_settrace.py
Original file line number Diff line number Diff line change
Expand Up @@ -2685,6 +2685,42 @@ def test_jump_with_null_on_stack_load_attr(output):
)
output.append(15)

@jump_test(2, 3, [1, 3])
def test_jump_extended_args_unpack_ex_simple(output):
output.append(1)
_, *_, _ = output.append(2) or "Spam"
output.append(3)

@jump_test(3, 4, [1, 4, 4, 5])
def test_jump_extended_args_unpack_ex_tricky(output):
output.append(1)
(
_, *_, _
) = output.append(4) or "Spam"
output.append(5)

def test_jump_extended_args_for_iter(self):
# In addition to failing when extended arg handling is broken, this can
# also hang for a *very* long time:
source = [
"def f(output):",
" output.append(1)",
" for _ in spam:",
*(f" output.append({i})" for i in range(3, 100_000)),
f" output.append(100_000)",
]
namespace = {}
exec("\n".join(source), namespace)
f = namespace["f"]
self.run_test(f, 2, 100_000, [1, 100_000])

@jump_test(2, 3, [1, 3])
def test_jump_or_pop(output):
output.append(1)
_ = output.append(2) and "Spam"
output.append(3)


class TestExtendedArgs(unittest.TestCase):

def setUp(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fix an issue that caused extended opcode arguments and some conditional pops
to be ignored when calculating valid jump targets for assignments to the
``f_lineno`` attribute of frame objects. In some cases, this could cause
inconsistent internal state, resulting in a hard crash of the interpreter.
13 changes: 9 additions & 4 deletions Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -319,11 +319,15 @@ mark_stacks(PyCodeObject *code_obj, int len)
int64_t target_stack;
int j = get_arg(code, i);
if (opcode == POP_JUMP_FORWARD_IF_FALSE ||
opcode == POP_JUMP_FORWARD_IF_TRUE) {
opcode == POP_JUMP_FORWARD_IF_TRUE ||
opcode == JUMP_IF_FALSE_OR_POP ||
opcode == JUMP_IF_TRUE_OR_POP)
{
j += i + 1;
}
else if (opcode == POP_JUMP_BACKWARD_IF_FALSE ||
opcode == POP_JUMP_BACKWARD_IF_TRUE) {
else {
assert(opcode == POP_JUMP_BACKWARD_IF_FALSE ||
opcode == POP_JUMP_BACKWARD_IF_TRUE);
j = i + 1 - j;
}
assert(j < len);
Expand Down Expand Up @@ -459,7 +463,8 @@ mark_stacks(PyCodeObject *code_obj, int len)
}
default:
{
int delta = PyCompile_OpcodeStackEffect(opcode, _Py_OPARG(code[i]));
int delta = PyCompile_OpcodeStackEffect(opcode, get_arg(code, i));
assert(delta != PY_INVALID_STACK_EFFECT);
while (delta < 0) {
next_stack = pop_value(next_stack);
delta++;
Expand Down

0 comments on commit e4d3a96

Please sign in to comment.