Skip to content

Commit de30ba5

Browse files
committed
Fix GH-16879: JIT dead code skipping does not update call_level
We intend to execute `MATCH_ERROR` in the VM and return to trace a hot function in BB1. We generate a tail handler and skip all remaining oplines of BB0. That means the `INIT_FCALL` in BB0 is missed and `call_level` is not increased to 1. This leads to the assertion failure. This patch fixes the issue by updating the `call_level` for the skipped oplines. Closes GH-16939.
1 parent 8fdcd9f commit de30ba5

File tree

3 files changed

+52
-1
lines changed

3 files changed

+52
-1
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ PHP NEWS
1919
. Fixed bug GH-16851 (JIT_G(enabled) not set correctly on other threads).
2020
(dktapps)
2121
. Fixed bug GH-16902 (Set of opcache tests fail zts+aarch64). (nielsdos)
22+
. Fixed bug GH-16879 (JIT dead code skipping does not update call_level).
23+
(nielsdos)
2224

2325
- Windows:
2426
. Fixed bug GH-16849 (Error dialog causes process to hang). (cmb)

ext/opcache/jit/zend_jit.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2576,7 +2576,34 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
25762576
}
25772577
/* THROW and EXIT may be used in the middle of BB */
25782578
/* don't generate code for the rest of BB */
2579-
i = end;
2579+
2580+
/* Skip current opline for call_level computation
2581+
* Don't include last opline because end of loop already checks call level of last opline */
2582+
i++;
2583+
for (; i < end; i++) {
2584+
opline = op_array->opcodes + i;
2585+
switch (opline->opcode) {
2586+
case ZEND_INIT_FCALL:
2587+
case ZEND_INIT_FCALL_BY_NAME:
2588+
case ZEND_INIT_NS_FCALL_BY_NAME:
2589+
case ZEND_INIT_METHOD_CALL:
2590+
case ZEND_INIT_DYNAMIC_CALL:
2591+
case ZEND_INIT_STATIC_METHOD_CALL:
2592+
case ZEND_INIT_PARENT_PROPERTY_HOOK_CALL:
2593+
case ZEND_INIT_USER_CALL:
2594+
case ZEND_NEW:
2595+
call_level++;
2596+
break;
2597+
case ZEND_DO_FCALL:
2598+
case ZEND_DO_ICALL:
2599+
case ZEND_DO_UCALL:
2600+
case ZEND_DO_FCALL_BY_NAME:
2601+
case ZEND_CALLABLE_CONVERT:
2602+
call_level--;
2603+
break;
2604+
}
2605+
}
2606+
opline = op_array->opcodes + i;
25802607
break;
25812608
/* stackless execution */
25822609
case ZEND_INCLUDE_OR_EVAL:

ext/opcache/tests/jit/gh16879.phpt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
GH-16879 (JIT dead code skipping does not update call_level)
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.enable=1
7+
opcache.enable_cli=1
8+
opcache.file_update_protection=0
9+
opcache.jit_buffer_size=32M
10+
opcache.jit=1235
11+
opcache.jit_hot_func=1
12+
--FILE--
13+
<?php
14+
match(0){};
15+
var_dump(new stdClass);
16+
var_dump(3);
17+
?>
18+
--EXPECTF--
19+
Fatal error: Uncaught UnhandledMatchError: Unhandled match case 0 in %s:%d
20+
Stack trace:
21+
#0 {main}
22+
thrown in %s on line %d

0 commit comments

Comments
 (0)