Commit 05c7b00d796 for php.net

commit 05c7b00d796be26aac15994803444519992dd78e
Author: Levi Morrison <levi.morrison@datadoghq.com>
Date:   Thu Jun 11 09:11:35 2026 -0600

    Fix another vm_interrupt bug for tailcall VM (#22265)

diff --git a/NEWS b/NEWS
index f09487c5da0..08d381209f8 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,9 @@ PHP                                                                        NEWS
     LXB_API as __declspec(dllimport) when linked statically into PHP.
     (Luther Monson)

+- Opcache:
+  . Fixed bug GH-22265 (Another tailcall vm_interrupt bug). (Levi Morrison)
+
 - Phar:
   . Fixed a bypass of the magic ".phar" directory protection in
     Phar::addEmptyDir() for paths starting with "/.phar", while allowing
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index 99e4cb13143..6405780f505 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -4302,8 +4302,15 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_fcall_interrupt(zend_execute_data *ca
 		} \
 	} while (0)

+#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
+# define ZEND_VM_KIND_TAILCALL_SAVE_OPLINE() SAVE_OPLINE()
+#else
+# define ZEND_VM_KIND_TAILCALL_SAVE_OPLINE()
+#endif
+
 #define ZEND_VM_LOOP_INTERRUPT_CHECK() do { \
 		if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { \
+			ZEND_VM_KIND_TAILCALL_SAVE_OPLINE(); \
 			ZEND_VM_LOOP_INTERRUPT(); \
 		} \
 	} while (0)
diff --git a/ext/zend_test/tests/observer_vm_interrupt_tailcall_return.phpt b/ext/zend_test/tests/observer_vm_interrupt_tailcall_return.phpt
new file mode 100644
index 00000000000..95af2681c25
--- /dev/null
+++ b/ext/zend_test/tests/observer_vm_interrupt_tailcall_return.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Observer: VM interrupt during tailcall return to caller
+--DESCRIPTION--
+This exercises a VM interrupt raised immediately before a user function returns
+to a caller that invoked it through DO_FCALL. On the tailcall VM, the caller's
+saved opline must point to the opcode after DO_FCALL before a pending interrupt
+is handled.
+--EXTENSIONS--
+zend_test
+--INI--
+opcache.jit=0
+zend_test.observer.set_vm_interrupt_on_begin=1
+--FILE--
+<?php
+function interrupt_before_return(VmInterruptComparable $left, VmInterruptComparable $right): void
+{
+    $left < $right;
+}
+
+function call_interrupt_before_return(): void
+{
+    interrupt_before_return(new VmInterruptComparable(2), new VmInterruptComparable(1));
+}
+
+call_interrupt_before_return();
+echo "ok\n";
+?>
+--EXPECT--
+ok