mirror of https://github.com/python/cpython
GH-94438: Handle extended arguments and conditional pops in mark_stacks (GH-95110)
This commit is contained in:
parent
900bfc53cb
commit
e4d3a96a11
|
@ -2685,6 +2685,42 @@ output.append(4)
|
|||
)
|
||||
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):
|
||||
|
|
|
@ -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.
|
|
@ -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);
|
||||
|
@ -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++;
|
||||
|
|
Loading…
Reference in New Issue