[PHP-CVS] [php-src] PHP-8.5: JIT: persist the SHM op_array in trace exit_info

[email protected] (Ilia Alshanetsky)
Newsgroups php.cvs
Message-ID <[email protected]>
Author: Ilia Alshanetsky (iliaal)
Date: 2026-08-24T09:28:01-04:00

Commit: https://github.com/php/php-src/commit/7873640e08e707c2cfbdf72daa10c592244a1cda
Raw diff: https://github.com/php/php-src/commit/7873640e08e707c2cfbdf72daa10c592244a1cda.diff

JIT: persist the SHM op_array in trace exit_info

exit_info.op_array was taken from the current frame. Methods of linked
classes that miss the inheritance cache use a heap copy of the op_array
header, so that pointer is invalid in other processes and later
requests. Store the original from the JIT extension, as root traces
already do.

Closes GH-21710

Changed paths:
  A  ext/opcache/tests/jit/gh21710.inc
  A  ext/opcache/tests/jit/gh21710.phpt
  M  NEWS
  M  ext/opcache/jit/zend_jit_trace.c


Diff:

diff --git a/NEWS b/NEWS
index d25d441ca8b5..a2c65685b4ce 100644
--- a/NEWS
+++ b/NEWS
@@ -33,6 +33,9 @@ PHP                                                                        NEWS
   . Fixed opcache.protect_memory race under ZTS. (realFlowControl)
   . Fixed bug GH-23288 (Crash on restart when opcache.interned_strings_buffer
     is overridden in an individual FPM pool). (David Carlier)
+  . Fixed a tracing JIT crash when compiling a side trace for a method of a
+    class that could not be stored in the inheritance cache. (GH-21710)
+    (Arnaud, iliaal)
 
 - PDO:
   . Fixed a leak when a persistent connection failed a liveness check
diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c
index 225257ecd6a4..6a3e8c3a4711 100644
--- a/ext/opcache/jit/zend_jit_trace.c
+++ b/ext/opcache/jit/zend_jit_trace.c
@@ -145,6 +145,11 @@ static uint32_t zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t
 	}
 	if (JIT_G(current_frame)) {
 		op_array = &JIT_G(current_frame)->func->op_array;
+		if (!(op_array->fn_flags & ZEND_ACC_IMMUTABLE)) {
+			zend_jit_op_array_trace_extension *jit_extension =
+				(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
+			op_array = jit_extension->op_array;
+		}
 		stack_size = op_array->last_var + op_array->T;
 		if (stack_size) {
 			stack = JIT_G(current_frame)->stack;
diff --git a/ext/opcache/tests/jit/gh21710.inc b/ext/opcache/tests/jit/gh21710.inc
new file mode 100644
index 000000000000..a727c8f12560
--- /dev/null
+++ b/ext/opcache/tests/jit/gh21710.inc
@@ -0,0 +1,15 @@
+<?php
+if (getenv('call_user_func')) {
+    eval('class P {}');
+}
+
+class C extends P {
+    static function f($v) {
+        return $v[0];
+        if ($a) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+}
diff --git a/ext/opcache/tests/jit/gh21710.phpt b/ext/opcache/tests/jit/gh21710.phpt
new file mode 100644
index 000000000000..d175ab4c7014
--- /dev/null
+++ b/ext/opcache/tests/jit/gh21710.phpt
@@ -0,0 +1,50 @@
+--TEST--
+GH-21710: tracing JIT side-trace compile with a heap-copied linked method
+--EXTENSIONS--
+opcache
+pcntl
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit=tracing
+opcache.jit_buffer_size=64M
+--ENV--
+call_user_func=call_user_func
+--SKIPIF--
+<?php
+if (!function_exists('pcntl_fork')) die('skip pcntl_fork() not available');
+if (!(opcache_get_status()['jit']['on'] ?? false)) die('skip JIT is not available');
+?>
+--FILE--
+<?php
+$pid = pcntl_fork();
+if ($pid === 0) {
+    require __DIR__ . '/gh21710.inc';
+    for ($i = 0; $i < 1000; $i++) {
+        getenv('call_user_func')('C::f', [false]);
+    }
+    exit(0);
+}
+if ($pid === -1) {
+    echo "pcntl_fork() failed\n";
+    exit(1);
+}
+
+pcntl_waitpid($pid, $status, 0);
+
+$buf = [];
+for ($i = 0; $i < 100; $i++) {
+    $buf[] = str_repeat('a', $i * 100);
+}
+
+require __DIR__ . '/gh21710.inc';
+
+for ($i = 0; $i < 1000; $i++) {
+    getenv('call_user_func')('C::f', [true]);
+}
+
+var_dump(getenv('call_user_func')('C::f', [true]));
+?>
+--EXPECT--
+bool(true)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.