Repository navigation
gh-161666: Fix undefined left shifts in stack_swap() - #161667
PavlNekrasov wants to merge 3 commits into
Conversation
Widen MASK and top to int64_t before shifting: shift can reach 60.
stack_swap() (Objects/frameobject.c)stack_swap()
|
Please follow the devguide when you create a PR (gh-NNNNNN: in the title, NEWS entries). |
| Kind top = top_of_stack(stack); | ||
| int shift = BITS_PER_BLOCK*(n-1); | ||
| int64_t replaced_low = (stack & ~(MASK << shift)) | (top << shift); | ||
| int64_t replaced_low = (stack & ~((int64_t)MASK << shift)) |
There was a problem hiding this comment.
stack_swap() still returns Kind (32-bit), so the result gets truncated once the stack has 11+ entries, even with the casts. The return type needs to be int64_t:
-static Kind
+static int64_t
stack_swap(int64_t stack, int n)It's visible from Python too: this jump is wrongly rejected with can't jump into the body of a for loop (passes without the swap line). Could go into JumpTestCase in Lib/test/test_sys_settrace.py:
def testbackwardjumpT(self):
src = ["def f(output):"]
src += [" " * (i + 1) + f"for a{i} in [0]:" for i in range(10)]
src += [" " * 11 + "output.append(1)",
" " * 11 + "output[0], a9 = a9, output[0]",
" " * 11 + "output.append(2)"]
ns = {}
exec("\n".join(src), ns)
self.run_test(ns["f"], 13, 11, [1, 1, 2])There was a problem hiding this comment.
damn the test I suggested is too deep. 10 loops overflows the stack model and hits the top_of_stack(next_stack) == Object assert in mark_stacks on debug builds, which is what's breaking CI (it happens on main too, with or without the swap line).
6 loops is enough: it still fails on main and passes with this PR.
def test_backward_jump_deep_stack(self):
src = ["def f(output):"]
src += [" " * (i + 1) + f"for a{i} in [0]:" for i in range(6)]
src += [" " * 7 + "output.append(1)",
" " * 7 + "output[0], a5 = a5, output[0]",
" " * 7 + "output.append(2)"]
ns = {}
exec("\n".join(src), ns)
self.run_test(ns["f"], 9, 7, [1, 1, 2])23042e8 to
a05ecf2
Compare
The 63-bit stack model was truncated to Kind (32-bit) on return; return int64_t and add a regression test.
a05ecf2 to
f45c3cf
Compare
Widen MASK and top to int64_t before shifting
stack_swap()#161666