From 3524702fe10a1bb3d7b583f9d0e2a0770f5ad5f9 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 10 Jan 2025 19:07:41 +0100 Subject: [PATCH] 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. Closes GH-17438. --- NEWS | 2 ++ ext/opcache/jit/zend_jit.c | 6 ++--- ext/opcache/tests/jit/gh17428.phpt | 35 ++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 ext/opcache/tests/jit/gh17428.phpt diff --git a/NEWS b/NEWS index a7cf2ebd6f4..3486f8764fe 100644 --- a/NEWS +++ b/NEWS @@ -44,6 +44,8 @@ PHP NEWS . Fixed bug GH-15981 (Segfault with frameless jumps and minimal JIT). (nielsdos) . Fixed bug GH-17307 (Internal closure causes JIT failure). (nielsdos) + . Fixed bug GH-17428 (Assertion failure ext/opcache/jit/zend_jit_ir.c:8940). + (nielsdos) - PHPDBG: . Fix crashes in function registration + test. (nielsdos, Girgias) diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 83837bb3454..77694e07d13 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2622,8 +2622,8 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op /* THROW and EXIT may be used in the middle of BB */ /* don't generate code for the rest of BB */ - /* Skip current opline for call_level computation - * Don't include last opline because end of loop already checks call level of last opline */ + /* Skip current opline for call_level computation because it does not influence call_level. + * Don't include last opline because end of loop already checks call level of last opline. */ i++; for (; i < end; i++) { opline = op_array->opcodes + i; @@ -2633,7 +2633,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op call_level--; } } - opline = op_array->opcodes + i; + opline = op_array->opcodes + end; break; /* stackless execution */ case ZEND_INCLUDE_OR_EVAL: diff --git a/ext/opcache/tests/jit/gh17428.phpt b/ext/opcache/tests/jit/gh17428.phpt new file mode 100644 index 00000000000..21bb1867632 --- /dev/null +++ b/ext/opcache/tests/jit/gh17428.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-17428 (Assertion failure ext/opcache/jit/zend_jit_ir.c:8940) +--EXTENSIONS-- +opcache +--INI-- +opcache.jit=1205 +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Error: Call to undefined function testConversion() in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d