Skip to content

Commit 4a63c4d

Browse files
committed
W22: fix bounds-check units mismatch (BCOffset bytes vs BCIndex count)
v2 28178f4 used 'BCOffset next_off = bci.nextInstrOffset(); if (next_off < bc_block.size())'. nextInstrOffset() returns BCOffset (bytes — see Python/jit/bytecode_offsets.h:115); bc_block.size() returns Py_ssize_t in instruction-count units (Python/jit/bytecode.cpp: 122 returns end_idx_ - start_idx_, both BCIndex). The integral comparison overload of BCOffset (bytecode_offsets.h:130) compares the byte value against the instruction count, so for any function past the first ~1 instruction the check evaluates FALSE and the deopt-throw is bypassed. Net effect: yield-from re-enters the JIT and W22 SIGABRT returns (caught by testkeeper 14:40:22Z STRICT VERIFY). Fix: assign nextInstrOffset() to BCIndex instead of BCOffset. The implicit BCIndex(BCOffset) constructor at bytecode_offsets.h:176 divides by sizeof(_Py_CODEUNIT)=2, matching the units of bc_block. size(). This is the exact pattern used at builder.cpp:1143 (the existing 3.11+ bounds-check precedent). Catch: testkeeper 14:40:22Z STRICT VERIFY DOUBLE FAIL — Criterion 1 yield-from auto-compile re-crashed with original W22 SIGABRT 134 (register v11 not live) at iter 999, await also still crashed at iter 1000 (same root cause: deopt-throw bypassed → YIELD_VALUE compiles → end-of-bytecode SIGSEGV in compiled path). Lesson (memory amendment): dis.dis fixture verification confirms oparg-mapping but does NOT confirm the C++ deopt-throw actually fires; runtime test (compile + execute + verify is_jit_compiled=False) is required for pattern-deopt commits.
1 parent 28178f4 commit 4a63c4d

1 file changed

Lines changed: 9 additions & 2 deletions

File tree

Python/jit/hir/builder.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4951,8 +4951,15 @@ void HIRBuilder::checkTranslate() {
49514951
// before reading the next instruction's opcode/oparg, otherwise
49524952
// YIELD_VALUE at end-of-bytecode SIGSEGVs reading garbage memory.
49534953
// (testkeeper 14:34:52Z auto-compile asyncio regression catch.)
4954-
BCOffset next_off = bci.nextInstrOffset();
4955-
if (next_off < bc_block.size()) {
4954+
//
4955+
// UNIT NOTE: nextInstrOffset() returns BCOffset (bytes); bc_block.size()
4956+
// returns Py_ssize_t in instruction-count units. Assigning to BCIndex
4957+
// auto-divides by sizeof(_Py_CODEUNIT) (per bytecode_offsets.h:176),
4958+
// matching the units of size(). This mirrors the existing 3.11+
4959+
// bounds-check pattern at builder.cpp:1143. (testkeeper 14:40:22Z
4960+
// catch on units mismatch in v2.)
4961+
BCIndex next_idx = bci.nextInstrOffset();
4962+
if (next_idx < bc_block.size()) {
49564963
auto next_bc = bci.nextInstr();
49574964
if (next_bc.opcode() == RESUME && next_bc.oparg() == 2) {
49584965
throw std::runtime_error{fmt::format(

0 commit comments

Comments
 (0)