From: Timofei <128279579+deadlovelll@users.noreply.github.com> Date: Tue, 30 Jun 2026 09:46:59 +0000 (+0300) Subject: gh-152192: Fix JUMP_BACKWARD passing a truncated oparg to the jit tracer (GH-152382) X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9e10f14b925562a0292c920608e24f89ee5f187e;p=thirdparty%2FPython%2Fcpython.git gh-152192: Fix JUMP_BACKWARD passing a truncated oparg to the jit tracer (GH-152382) --- diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 2248920c266a..25b2c393e677 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -1,4 +1,5 @@ import contextlib +import dis import itertools import sys import textwrap @@ -247,6 +248,28 @@ class TestUops(unittest.TestCase): self.assertTrue(any((opcode, oparg, operand) == ("_LOAD_FAST_BORROW", 259, 0) for opcode, oparg, _, operand in list(ex))) + def test_jump_backward_extended_arg(self): + # gh-152192: a JUMP_BACKWARD that needs an EXTENDED_ARG must record its + # deopt target at the EXTENDED_ARG, not the JUMP_BACKWARD. + ns = {} + src = ("def f(n):\n" + " i = 0\n" + " while i < n:\n" + " i += 1\n" + + "".join(f" a = {j}\n" for j in range(140))) + exec(src, ns) + f = ns["f"] + + instrs = list(dis.get_instructions(f)) + ext, jb = next((p, i) for p, i in zip(instrs, instrs[1:]) + if i.opname == "JUMP_BACKWARD" and p.opname == "EXTENDED_ARG") + + f(TIER2_THRESHOLD + 1) + ex = _opcode.get_executor(f.__code__, ext.offset) + set_ips = {t for op, _, t, _ in ex if op == "_SET_IP"} + self.assertIn(ext.offset // 2, set_ips) + self.assertNotIn(jb.offset // 2, set_ips) + def test_unspecialized_unpack(self): # An example of an unspecialized opcode def testfunc(x): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-38-21.gh-issue-152192.lX2jIM.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-38-21.gh-issue-152192.lX2jIM.rst new file mode 100644 index 000000000000..153cbeb317a2 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-38-21.gh-issue-152192.lX2jIM.rst @@ -0,0 +1,2 @@ +Fix a truncated ``oparg`` being passed to JIT trace initialization for a +``JUMP_BACKWARD`` with an ``EXTENDED_ARG``. diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index fdc077c9549a..51234e8749de 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -8582,8 +8582,7 @@ (this_instr->op.code == JUMP_BACKWARD_JIT || is_resume)) && next_instr->op.code != ENTER_EXECUTOR) { _Py_CODEUNIT *insert_exec_at = this_instr; - while (oparg > 255) { - oparg >>= 8; + for (int tmp = oparg; tmp > 255; tmp >>= 8) { insert_exec_at--; } int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, @@ -11575,8 +11574,7 @@ (this_instr->op.code == JUMP_BACKWARD_JIT || is_resume)) && next_instr->op.code != ENTER_EXECUTOR) { _Py_CODEUNIT *insert_exec_at = this_instr; - while (oparg > 255) { - oparg >>= 8; + for (int tmp = oparg; tmp > 255; tmp >>= 8) { insert_exec_at--; } int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 31596e0bc7a3..7fb48516e2ea 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3560,8 +3560,8 @@ dummy_func( next_instr->op.code != ENTER_EXECUTOR) { /* Back up over EXTENDED_ARGs so executor is inserted at the correct place */ _Py_CODEUNIT *insert_exec_at = this_instr; - while (oparg > 255) { - oparg >>= 8; + // gh-152192: count with a temporary. oparg must stay intact, it's passed to the tracer below + for (int tmp = oparg; tmp > 255; tmp >>= 8) { insert_exec_at--; } int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 0da86abed67f..4b472aecc5fc 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8581,8 +8581,7 @@ (this_instr->op.code == JUMP_BACKWARD_JIT || is_resume)) && next_instr->op.code != ENTER_EXECUTOR) { _Py_CODEUNIT *insert_exec_at = this_instr; - while (oparg > 255) { - oparg >>= 8; + for (int tmp = oparg; tmp > 255; tmp >>= 8) { insert_exec_at--; } int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, @@ -11572,8 +11571,7 @@ (this_instr->op.code == JUMP_BACKWARD_JIT || is_resume)) && next_instr->op.code != ENTER_EXECUTOR) { _Py_CODEUNIT *insert_exec_at = this_instr; - while (oparg > 255) { - oparg >>= 8; + for (int tmp = oparg; tmp > 255; tmp >>= 8) { insert_exec_at--; } int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at,