https://github.com/python/cpython/commit/9e10f14b925562a0292c920608e24f89ee5f187e
commit: 9e10f14b925562a0292c920608e24f89ee5f187e
branch: main
author: Timofei <[email protected]>
committer: markshannon <[email protected]>
date: 2026-06-30T10:46:59+01:00
summary:

gh-152192: Fix JUMP_BACKWARD passing a truncated oparg to the jit tracer 
(GH-152382)

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-38-21.gh-issue-152192.lX2jIM.rst
M Lib/test/test_capi/test_opt.py
M Modules/_testinternalcapi/test_cases.c.h
M Python/bytecodes.c
M Python/generated_cases.c.h

diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py
index 2248920c266aef5..25b2c393e6773de 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 @@ def many_vars():
         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 000000000000000..153cbeb317a2452
--- /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 fdc077c9549a144..51234e8749de261 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 31596e0bc7a31d2..7fb48516e2eae73 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 0da86abed67f63b..4b472aecc5fc3aa 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,

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to