From 60ae89be22ba4c3dc0a98454f792d72d089ecc63 Mon Sep 17 00:00:00 2001 From: ndossche <7771979+ndossche@users.noreply.github.com> Date: Fri, 30 Oct 2026 21:22:03 +0100 Subject: [PATCH 1/2] Fix GH-24988: Incorrect opcode range check causes bugs with exceptions in function JIT `range->var` is a byte offset, but `var_num` is an index, so we have to convert the index to the byte offset using `EX_NUM_TO_VAR()`. This matches `cleanup_live_vars()` code. --- ext/opcache/jit/zend_jit.c | 2 +- ext/opcache/tests/jit/gh24988.phpt | 34 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 ext/opcache/tests/jit/gh24988.phpt diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 30169921173b..bb79ca8a2669 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -1164,7 +1164,7 @@ static void zend_jit_allocate_registers(zend_jit_ctx *ctx, const zend_op_array * if (range->start > op_num) { /* further blocks will not be relevant... */ break; - } else if (op_num < range->end && var_num == (range->var & ~ZEND_LIVE_MASK)) { + } else if (op_num < range->end && EX_NUM_TO_VAR(var_num) == (range->var & ~ZEND_LIVE_MASK)) { /* check if opcodes in range may throw */ do { if (zend_may_throw(op_array->opcodes + op_num, ssa->ops + op_num, op_array, ssa)) { diff --git a/ext/opcache/tests/jit/gh24988.phpt b/ext/opcache/tests/jit/gh24988.phpt new file mode 100644 index 000000000000..4f4eec9ebed3 --- /dev/null +++ b/ext/opcache/tests/jit/gh24988.phpt @@ -0,0 +1,34 @@ +--TEST-- +GH-24988 (JIT: crash in cleanup_live_vars when % by zero throws mid-expression) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit_buffer_size=64M +opcache.jit=function +opcache.optimization_level=0 +--EXTENSIONS-- +opcache +--FILE-- +getMessage(); +} +var_dump($out); + +?> +--EXPECT-- +array(2) { + [0]=> + int(9) + [1]=> + string(14) "Modulo by zero" +} From 63f6d7a9531d528f8d59d2349b9bedfaccd828ec Mon Sep 17 00:00:00 2001 From: ndossche <7771979+ndossche@users.noreply.github.com> Date: Sat, 31 Oct 2026 16:17:06 +0100 Subject: [PATCH 2/2] Update test Co-authored-by: Jorg Sowa --- ext/opcache/tests/jit/gh24988.phpt | 31 +++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/ext/opcache/tests/jit/gh24988.phpt b/ext/opcache/tests/jit/gh24988.phpt index 4f4eec9ebed3..f8cd56e5bec1 100644 --- a/ext/opcache/tests/jit/gh24988.phpt +++ b/ext/opcache/tests/jit/gh24988.phpt @@ -1,5 +1,8 @@ --TEST-- GH-24988 (JIT: crash in cleanup_live_vars when % by zero throws mid-expression) +--CREDITS-- +waroad +jorgsowa --INI-- opcache.enable=1 opcache.enable_cli=1 @@ -11,24 +14,34 @@ opcache --FILE-- self()->self(); +} + function deep(int $a, int $b, int $c) { $a &= 255; return ($a + 1) - ($b + $b + (($a + 1) % ($b % $c))); } -$out = [deep(15, 3, 7)]; +$o = new D; +var_dump(deep(15, 3, 7)); +pollute($o, 1, 2); try { deep(15, 3, 0); } catch (DivisionByZeroError $e) { - $out[] = $e->getMessage(); + echo $e->getMessage(), "\n"; } -var_dump($out); +echo "end\n"; ?> --EXPECT-- -array(2) { - [0]=> - int(9) - [1]=> - string(14) "Modulo by zero" -} +int(9) +Modulo by zero +end +dtor