From 460ffba5091234f14e0a85b9dabaa502f9341653 Mon Sep 17 00:00:00 2001 From: Rafael Molina Date: Thu, 5 Nov 2026 17:42:58 -0300 Subject: [PATCH] Fixed GH-25220: Clear leftover func_info after JIT setup failure. When hot-counter JIT setup runs out of shared memory mid-script, the remaining op_arrays kept pointers into the released call-graph arena. Clear those FUNC_INFO slots on the delayed-trigger jit_failure path. --- NEWS | 2 + ext/opcache/jit/zend_jit.c | 6 +++ ext/opcache/tests/jit/gh25220.phpt | 68 ++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 ext/opcache/tests/jit/gh25220.phpt diff --git a/NEWS b/NEWS index 6fde7abcbc48..a422d1d68237 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,8 @@ PHP NEWS . Fixed curl_reset() retaining CURLOPT_PRIVATE after reset. (lacatoire) - Opcache: + . Fixed bug GH-25220 (JIT hot counters segfault when shared memory is + exhausted during script JIT setup). (rafamolina1) . Fixed bug GH-25165 (Tracing JIT loops forever once opcache.jit_buffer_size is exhausted while compiling side traces). (Ilia Alshanetsky) . Fixed bug GH-25164 (Function JIT loop calling a user function runs once diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index dbc7a37ca079..9f74aa6c40cf 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -3388,6 +3388,12 @@ int zend_jit_script(zend_script *script) for (i = 0; i < call_graph.op_arrays_count; i++) { ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL); } + } else { + /* Remaining op_arrays still point at func_info in the arena + released below. Already-setup ones keep their SHM jit_extension. */ + for (; i < call_graph.op_arrays_count; i++) { + ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL); + } } zend_arena_release(&CG(arena), checkpoint); return FAILURE; diff --git a/ext/opcache/tests/jit/gh25220.phpt b/ext/opcache/tests/jit/gh25220.phpt new file mode 100644 index 000000000000..b1a0610b0464 --- /dev/null +++ b/ext/opcache/tests/jit/gh25220.phpt @@ -0,0 +1,68 @@ +--TEST-- +GH-25220 (JIT hot counters segfault when shared memory is exhausted during script JIT setup) +--EXTENSIONS-- +opcache +--SKIPIF-- + +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=1235 +opcache.jit_buffer_size=64M +opcache.jit_hot_func=1 +opcache.memory_consumption=8 +opcache.max_accelerated_files=10000 +opcache.interned_strings_buffer=1 +opcache.file_update_protection=0 +opcache.validate_timestamps=0 +opcache.jit_max_root_traces=1024 +opcache.jit_max_side_traces=128 +opcache.jit_max_exit_counters=8192 +memory_limit=-1 +--FILE-- +m$k(\$x + $k);\n"; + $m .= " public function m$k(int \$x): int { \$t = \$x + $k; return \$t > 3 ? \$t : \$t + $k; }\n"; + } + file_put_contents("$dir/C$i.php", + "m0(1); + $sum += $o->m0(2); + } +} + +echo "ok\n"; +?> +--CLEAN-- + +--EXPECT-- +ok