Skip to content

Commit 80dcc05

Browse files
committed
Fix GH-17428: Assertion failure ext/opcache/jit/zend_jit_ir.c:8940
The code to update the call_level in that case skips the opline itself, as that's handled by the tail handler, and then wants to set the opline to the last opline of the block because the code below the switch will update the call_level for that opline. However, the test has a block with a single opline (THROW). The block after that has ZEND_INIT_FCALL, because `i` points to ZEND_INIT_FCALL now, it erroneously causes the call_level after the switch. Although it suffices to change `i` to `end` (none of the opcodes here occur in `zend_jit_dec_call_level`), I added a goto label as well to be safer for the future in case the list of opcodes changes.
1 parent 27fbdc1 commit 80dcc05

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2622,19 +2622,18 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
26222622
/* THROW and EXIT may be used in the middle of BB */
26232623
/* don't generate code for the rest of BB */
26242624

2625-
/* Skip current opline for call_level computation
2626-
* Don't include last opline because end of loop already checks call level of last opline */
2625+
/* Skip current opline for call_level computation. */
26272626
i++;
2628-
for (; i < end; i++) {
2627+
for (; i <= end; i++) {
26292628
opline = op_array->opcodes + i;
26302629
if (zend_jit_inc_call_level(opline->opcode)) {
26312630
call_level++;
26322631
} else if (zend_jit_dec_call_level(opline->opcode)) {
26332632
call_level--;
26342633
}
26352634
}
2636-
opline = op_array->opcodes + i;
2637-
break;
2635+
opline = op_array->opcodes + end;
2636+
goto done_no_dec_call_level;
26382637
/* stackless execution */
26392638
case ZEND_INCLUDE_OR_EVAL:
26402639
case ZEND_DO_FCALL:
@@ -2727,6 +2726,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
27272726
if (zend_jit_dec_call_level(opline->opcode)) {
27282727
call_level--;
27292728
}
2729+
done_no_dec_call_level:;
27302730
}
27312731
zend_jit_bb_end(&ctx, b);
27322732
}

ext/opcache/tests/jit/gh17428.phpt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
GH-17428 (Assertion failure ext/opcache/jit/zend_jit_ir.c:8940)
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.jit=1205
7+
--FILE--
8+
<?php
9+
new EmptyIterator();
10+
srand(1000);
11+
error_reporting(E_ALL);
12+
testConversion('', '');
13+
testConversion('', '');
14+
testConversion('', '');
15+
testConversion('', '');
16+
testConversion('', '');
17+
function testRoundTrip($data) {
18+
}
19+
for ($iterations = 0; $iterations < 100; $iterations++) {
20+
$strlen = rand(1, 100);
21+
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
22+
$randstring = '';
23+
for ($i = 0; $i < $strlen; $i++) {
24+
$randstring .= $characters[rand(0, strlen($characters) - 1)];
25+
}
26+
die($randstring);
27+
}
28+
echo "Done!\n";
29+
throw new Hello(new stdClass);
30+
?>
31+
--EXPECTF--
32+
Fatal error: Uncaught Error: Call to undefined function testConversion() in %s:%d
33+
Stack trace:
34+
#0 {main}
35+
thrown in %s on line %d

0 commit comments

Comments
 (0)