[php-src] master: Merge branch 'PHP-8.6'
| From: | David Carlier | Date: | Fri, 09 Oct 2026 12:26:47 +0000 |
| Subject: | [php-src] master: Merge branch 'PHP-8.6' | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-142114@lists.php.net to get a copy of this message | ||
Author: David Carlier (devnexen)
Date: 2026-10-09T13:26:24+01:00
Commit: https://github.com/php/php-src/commit/e8ccbe78b2b48d798862a1f73d14de0b5acc7fa9
Raw diff: https://github.com/php/php-src/commit/e8ccbe78b2b48d798862a1f73d14de0b5acc7fa9.diff
Merge branch 'PHP-8.6'
* PHP-8.6:
Fix GH-24081: User opcode DISPATCH runs on a stale frame in the TAILCALL VM
Changed paths:
A ext/zend_test/tests/gh24081.phpt
M Zend/zend_vm_execute.h
M Zend/zend_vm_gen.php
Diff:
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 1b30ad218f23..8ab294f24c38 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -336,7 +336,7 @@ static zend_vm_opcode_handler_func_t const * zend_opcode_handler_funcs;
static const zend_op call_interrupt_op;
#endif
-#if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID && ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL) ||
!ZEND_VM_SPEC
+#if ZEND_VM_KIND != ZEND_VM_KIND_HYBRID || !ZEND_VM_SPEC
static zend_vm_opcode_handler_t zend_vm_get_opcode_handler(uint8_t opcode, const zend_op* op);
#endif
@@ -53712,6 +53712,7 @@ static ZEND_COLD zend_never_inline ZEND_OPCODE_HANDLER_RET
ZEND_OPCODE_HANDLER_F
# undef ZEND_VM_INTERRUPT
# undef ZEND_VM_ENTER_EX
# undef ZEND_VM_LEAVE
+# undef ZEND_VM_DISPATCH
# define ZEND_VM_TAIL_CALL(call) ZEND_MUSTTAIL return call
# define ZEND_VM_CONTINUE()
ZEND_VM_TAIL_CALL(opline->handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))
@@ -53725,6 +53726,7 @@ static ZEND_COLD zend_never_inline ZEND_OPCODE_HANDLER_RET
ZEND_OPCODE_HANDLER_F
# define ZEND_VM_INTERRUPT()
ZEND_VM_TAIL_CALL(zend_interrupt_TAILCALL(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))
# define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()
# define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()
+# define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(zend_vm_get_opcode_handler(opcode,
opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))
static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV
zend_interrupt_helper_SPEC_TAILCALL(ZEND_OPCODE_HANDLER_ARGS);
static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV
zend_interrupt(ZEND_OPCODE_HANDLER_ARGS);
@@ -123417,7 +123419,7 @@ static uint32_t ZEND_FASTCALL zend_vm_get_opcode_handler_idx(uint32_t
spec, cons
return (spec & SPEC_START_MASK) + offset;
}
-#if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID && ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL) ||
!ZEND_VM_SPEC
+#if ZEND_VM_KIND != ZEND_VM_KIND_HYBRID || !ZEND_VM_SPEC
static zend_vm_opcode_handler_t zend_vm_get_opcode_handler(uint8_t opcode, const zend_op* op)
{
return zend_opcode_handlers[zend_vm_get_opcode_handler_idx(zend_spec_handlers[opcode], op)];
diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php
index 674d1ed5b673..57b718fcf76a 100755
--- a/Zend/zend_vm_gen.php
+++ b/Zend/zend_vm_gen.php
@@ -1917,7 +1917,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name,
$initializer_name)
out($f,"static const zend_op call_interrupt_op;\n");
out($f,"#endif\n\n");
}
- out($f,"#if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID && ZEND_VM_KIND
!= ZEND_VM_KIND_TAILCALL) || !ZEND_VM_SPEC\n");
+ out($f,"#if ZEND_VM_KIND != ZEND_VM_KIND_HYBRID || !ZEND_VM_SPEC\n");
out($f,"static zend_vm_opcode_handler_t zend_vm_get_opcode_handler(uint8_t
opcode, const zend_op* op);\n");
out($f,"#endif\n\n");
if ($kind == ZEND_VM_KIND_HYBRID) {
@@ -2146,6 +2146,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name,
$initializer_name)
out($f,"# undef ZEND_VM_INTERRUPT\n");
out($f,"# undef ZEND_VM_ENTER_EX\n");
out($f,"# undef ZEND_VM_LEAVE\n");
+ out($f,"# undef ZEND_VM_DISPATCH\n");
out($f,"\n");
out($f,"# define ZEND_VM_TAIL_CALL(call) ZEND_MUSTTAIL
return call\n");
out($f,"# define ZEND_VM_CONTINUE()
ZEND_VM_TAIL_CALL(opline->handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))\n");
@@ -2159,6 +2160,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name,
$initializer_name)
out($f,"# define ZEND_VM_INTERRUPT()
ZEND_VM_TAIL_CALL(zend_interrupt_TAILCALL(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))\n");
out($f,"# define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK();
ZEND_VM_CONTINUE()\n");
out($f,"# define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n");
+ out($f,"# define ZEND_VM_DISPATCH(opcode, opline)
ZEND_VM_TAIL_CALL(zend_vm_get_opcode_handler(opcode,
opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))\n");
out($f,"\n");
out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV
zend_interrupt_helper".($spec?"_SPEC":"")."_TAILCALL(ZEND_OPCODE_HANDLER_ARGS);\n");
out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV
zend_interrupt(ZEND_OPCODE_HANDLER_ARGS);\n");
@@ -3042,7 +3044,7 @@ function gen_vm($def, $skel) {
out($f, "\treturn (spec & SPEC_START_MASK) + offset;\n");
}
out($f, "}\n\n");
- out($f, "#if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID && ZEND_VM_KIND !=
ZEND_VM_KIND_TAILCALL) || !ZEND_VM_SPEC\n");
+ out($f, "#if ZEND_VM_KIND != ZEND_VM_KIND_HYBRID || !ZEND_VM_SPEC\n");
out($f, "static zend_vm_opcode_handler_t zend_vm_get_opcode_handler(uint8_t opcode, const
zend_op* op)\n");
out($f, "{\n");
if (!ZEND_VM_SPEC) {
diff --git a/ext/zend_test/tests/gh24081.phpt b/ext/zend_test/tests/gh24081.phpt
new file mode 100644
index 000000000000..96119454bf69
--- /dev/null
+++ b/ext/zend_test/tests/gh24081.phpt
@@ -0,0 +1,24 @@
+--TEST--
+GH-24081 (User opcode handlers resume execution against a stale frame under ZEND_VM_KIND_TAILCALL)
+--EXTENSIONS--
+zend_test
+--INI--
+opcache.jit=disable
+zend_test.observer.enabled=1
+zend_test.observer.show_opcode_in_user_handler=ZEND_ADD
+--FILE--
+<?php
+function f($a, $b) {
+ $r = $a + $b;
+ return strlen("x") + $r;
+}
+
+var_dump(f(1, 2));
+?>
+--EXPECTF--
+<!-- init '%s' -->
+<!-- init f() -->
+<!-- opcode: 'ZEND_ADD' in user handler -->
+<!-- opcode: 'ZEND_ADD' in user handler -->
+<!-- init var_dump() -->
+int(4)