Skip to content

Commit 853b89c

Browse files
authored
Clear ZREG_TYPE_ONLY flag for in-register vars in zend_jit_snapshot_handler() (#22764)
Fixes GH-22763. The reproducer triggers an assertion failure in `zend_jit_use_reg()` because a var has `jit->ra[var].ref == IR_NULL` but `jit->ra[var].flags` doesn't contain `ZREG_LOAD`. This happens because of the following events: * An in-register variable is spilled to the VM stack frame by IR (IR_REG_SPILL_SPECIAL) * zend_jit_snapshot_handler() set the stack descriptor to .flags = ZREG_TYPE_ONLY, .reg = ZREG_NONE * During a subsequent call to zend_jit_snapshot_handler(), the reg is not IR_REG_SPILL_SPECIAL anymore, so .reg is set but .flags remains ZREG_TYPE_ONLY which is inconsistent * A side trace inherits from this stack descriptor * zend_jit_trace_deoptimization() doesn't set `jit->ra[var].ref` for this var because `.flags == ZREG_TYPE_ONLY`, which causes the assertion failure later Fix by removing irrelevant flags when setting reg in zend_jit_snapshot_handler().
1 parent 6e74914 commit 853b89c

3 files changed

Lines changed: 63 additions & 1 deletion

File tree

ext/opcache/jit/zend_jit_ir.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -859,12 +859,14 @@ void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snaps
859859
t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
860860
} else {
861861
if ((exit_flags & ZEND_JIT_EXIT_FIXED)
862-
&& t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)) {
862+
&& (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)
863+
|| (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags & ~(ZREG_LOAD|ZREG_STORE|ZREG_LAST_USE)))) {
863864
exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
864865
addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
865866
exit_flags &= ~ZEND_JIT_EXIT_FIXED;
866867
}
867868
t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
869+
t->stack_map[t->exit_info[exit_point].stack_offset + var].flags &= (ZREG_LOAD|ZREG_STORE|ZREG_LAST_USE);
868870
}
869871
} else {
870872
if ((exit_flags & ZEND_JIT_EXIT_FIXED)

ext/opcache/jit/zend_jit_trace.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3558,6 +3558,8 @@ static int zend_jit_trace_deoptimization(
35583558
}
35593559
}
35603560
} else if (STACK_FLAGS(parent_stack, i) == ZREG_TYPE_ONLY) {
3561+
ZEND_ASSERT(reg == ZREG_NONE);
3562+
35613563
uint8_t type = STACK_TYPE(parent_stack, i);
35623564

35633565
if (!zend_jit_store_type(jit, i, type)) {

ext/opcache/tests/jit/gh22763.phpt

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
GH-22763: JIT fails to clear ZREG_TYPE_ONLY after setting reg
3+
--FILE--
4+
<?php
5+
6+
function findMiddleSnake(array $a, int $aLo, int $aHi, array $b, int $bLo, int $bHi): array
7+
{
8+
$n = $aHi - $aLo;
9+
$m = $bHi - $bLo;
10+
$delta = $n - $m;
11+
$deltaIsOdd = ($delta & 1) !== 0;
12+
$offset = 4;
13+
$size = 2 * 3 + 2;
14+
$vf = array_fill(0, $size, 0);
15+
$vb = array_fill(0, $size, 0);
16+
17+
$d = 2;
18+
$x = 0;
19+
20+
for ($k = -$d; $k <= $d; $k += 2) {
21+
if ($k === -$d || ($k !== $d && $vb[$offset + $k - 1] < $vb[$offset + $k + 1])) {
22+
$x = $vb[$offset + $k + 1];
23+
var_dump($x);
24+
} else {
25+
$x = $vb[$offset + $k - 1] + 1;
26+
}
27+
28+
$y = $x - $k;
29+
$xs = $x;
30+
$ys = $y;
31+
32+
while ($x < $n && $y < $m && $a[$aLo + $n - 1 - $x] === $b[$bLo + $m - 1 - $y]) {
33+
$x++;
34+
$y++;
35+
}
36+
37+
$vb[$offset + $k] = $x;
38+
39+
if (!$deltaIsOdd) {
40+
$kf = $delta - $k;
41+
42+
if ($kf >= -$d && $kf <= $d && $vf[$offset + $kf] + $vb[$offset + $k] >= $n) {
43+
return [$n - $x, $m - $y, $n - $xs, $m - $ys];
44+
}
45+
}
46+
}
47+
48+
return [];
49+
}
50+
51+
$from = [3,2,1];
52+
$to = [1,99,3];
53+
findMiddleSnake($from, 0, count($from), $to, 0, count($to));
54+
?>
55+
--EXPECTF--
56+
int(0)
57+
58+
Warning: Undefined array key 3 in %s on line %d

0 commit comments

Comments
 (0)