Commit 6872432adf1 for php.net
commit 6872432adf1a8ddd09a06385512003b1e1a0c916
Author: Arnaud Le Blanc <arnaud.lb@gmail.com>
Date: Mon Apr 27 17:39:42 2026 +0200
Fix incorrect trace stop type
Restores 79aaeea, which was likely lost in the rebase of 76d7c61
Fixes GH-21746
Closes GH-21891
diff --git a/NEWS b/NEWS
index 64c9f13cc57..abd76d8555f 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,7 @@ PHP NEWS
- Opcache:
. Fixed tracing JIT crash when a VM interrupt is handled during an observed
user function call. (Levi Morrison)
+ . Fixed bug GH-21746 (Segfault with tracing JIT). (Arnaud)
- OpenSSL:
. Fix compatibility issues with OpenSSL 4.0. (jordikroon, Remi)
diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c
index cb896c0cd8c..44f46feb5f6 100644
--- a/ext/opcache/jit/zend_jit_vm_helpers.c
+++ b/ext/opcache/jit/zend_jit_vm_helpers.c
@@ -1097,6 +1097,8 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
if (UNEXPECTED(!jit_extension)
|| UNEXPECTED(!(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE))) {
if (execute_data->prev_execute_data != prev_execute_data) {
+ stop = ZEND_JIT_TRACE_STOP_RETURN;
+ } else {
stop = ZEND_JIT_TRACE_STOP_INTERPRETER;
}
break;
diff --git a/ext/opcache/tests/jit/gh21746.inc b/ext/opcache/tests/jit/gh21746.inc
new file mode 100644
index 00000000000..b118625484d
--- /dev/null
+++ b/ext/opcache/tests/jit/gh21746.inc
@@ -0,0 +1,16 @@
+<?php
+return function (mixed $in = null, array $options = []) {
+ $a = null;
+ $b = '';
+ $c = '';
+ $d = fn() => '';
+ $e = fn() => '';
+ $f = fn() => '';
+ $g = fn() => '';
+ return ''
+ .LR::p(null, '', null, [], '')
+ .LR::hbbch([null], $d)
+ .LR::hbbch([null], $e)
+ .LR::hbbch([null], $f)
+ .LR::hbbch([null], $g);
+};
diff --git a/ext/opcache/tests/jit/gh21746.phpt b/ext/opcache/tests/jit/gh21746.phpt
new file mode 100644
index 00000000000..29b3be778be
--- /dev/null
+++ b/ext/opcache/tests/jit/gh21746.phpt
@@ -0,0 +1,112 @@
+--TEST--
+GH-21746: Segfault with tracing JIT on 2nd call of eval'd closure
+--CREDITS--
+theodorejb
+--EXTENSIONS--
+opcache
+--INI--
+opcache.jit=tracing
+--FILE--
+<?php
+
+final class LR {
+ public static function p(mixed $cx, string $name, mixed $context, array $hash, string $indent): string {
+ try { $result = ''; } finally {}
+ $lines = explode("\n", $result);
+ foreach ($lines as $i => $_) { if ($i === 0) break; }
+ return $result;
+ }
+ public static function hbbch(array $positional, ?\Closure $cb): string {
+ if ($cb && is_array($positional[0] ?? null)) foreach ($positional[0] as $v) $cb($v);
+ return '';
+ }
+}
+
+$renderFile = __DIR__ . '/gh21746.inc';
+
+// prevent JITing $renderFile
+ini_set('opcache.file_update_protection', 100);
+touch($renderFile);
+
+$renderer = require $renderFile;
+
+for ($r = 0; $r < 70; $r++) {
+ echo "Render $r...";
+ $renderer();
+ echo "OK\n";
+}
+
+?>
+==DONE==
+--EXPECT--
+Render 0...OK
+Render 1...OK
+Render 2...OK
+Render 3...OK
+Render 4...OK
+Render 5...OK
+Render 6...OK
+Render 7...OK
+Render 8...OK
+Render 9...OK
+Render 10...OK
+Render 11...OK
+Render 12...OK
+Render 13...OK
+Render 14...OK
+Render 15...OK
+Render 16...OK
+Render 17...OK
+Render 18...OK
+Render 19...OK
+Render 20...OK
+Render 21...OK
+Render 22...OK
+Render 23...OK
+Render 24...OK
+Render 25...OK
+Render 26...OK
+Render 27...OK
+Render 28...OK
+Render 29...OK
+Render 30...OK
+Render 31...OK
+Render 32...OK
+Render 33...OK
+Render 34...OK
+Render 35...OK
+Render 36...OK
+Render 37...OK
+Render 38...OK
+Render 39...OK
+Render 40...OK
+Render 41...OK
+Render 42...OK
+Render 43...OK
+Render 44...OK
+Render 45...OK
+Render 46...OK
+Render 47...OK
+Render 48...OK
+Render 49...OK
+Render 50...OK
+Render 51...OK
+Render 52...OK
+Render 53...OK
+Render 54...OK
+Render 55...OK
+Render 56...OK
+Render 57...OK
+Render 58...OK
+Render 59...OK
+Render 60...OK
+Render 61...OK
+Render 62...OK
+Render 63...OK
+Render 64...OK
+Render 65...OK
+Render 66...OK
+Render 67...OK
+Render 68...OK
+Render 69...OK
+==DONE==