Commit bf4b9265442 for php.net
commit bf4b926544299d6650d7517c1927bf56c7d84ab0
Merge: 5ee37f68279 40c3e247f9b
Author: Arnaud Le Blanc <arnaud.lb@gmail.com>
Date: Thu Jul 30 09:47:46 2026 +0200
Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
CS
Fix GH-22857: Function JIT emits wrong code for FETCH_OBJ_FUNC_ARG on a property hook (#22897)
diff --cc NEWS
index 28a4ef939ea,7f4d24f6b0a..3282ce1435b
--- a/NEWS
+++ b/NEWS
@@@ -11,12 -8,9 +11,14 @@@ PH
- DOM:
. Fixed bug GH-22825 (DOMElement::setAttribute() fails silently when the DTD
declares a default value for the attribute). (iliaal)
- . Fixed bug GH-22447 (UAF at dom_objects_free_storage when setting an
- attribute node that collides by local name with a namespaced
- attribute). (David Carlier)
+
+- Opcache:
+ . Fixed GH-22693 (DT_TEXTREL in JIT-generated TLS access on x86_64).
+ (David Carlier)
+ . Fixed bug GH-22763 (JIT fails to clear ZREG_TYPE_ONLY after setting reg).
+ (Arnaud)
++ . Fixed bug GH-22857 (Function JIT emits wrong code for FETCH_OBJ_FUNC_ARG on
++ a property hook getter, losing register-held variables). (Zhao Hao)
- MBString:
. Fixed bug GH-22779 (mb_strrpos() returns the wrong position for a negative
diff --cc ext/opcache/jit/zend_jit.c
index 5de9c81484b,a958a2453c4..76510743d33
--- a/ext/opcache/jit/zend_jit.c
+++ b/ext/opcache/jit/zend_jit.c
@@@ -2483,29 -2370,33 +2484,49 @@@ static int zend_jit(const zend_op_arra
|| Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
break;
}
- if (!zend_jit_fetch_obj(&ctx, opline, op_array, ssa, ssa_op,
- op1_info, op1_addr, 0, ce, ce_is_instanceof, on_this, 0, 0, NULL,
- RES_REG_ADDR(), IS_UNKNOWN,
- zend_may_throw(opline, ssa_op, op_array, ssa))) {
- goto jit_failure;
+ if (opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG) {
+ /* FETCH_OBJ_FUNC_ARG's by-value fetch dispatches into the
+ * FETCH_OBJ_R handler, which may take the SIMPLE_GET hook fast
+ * path and push a getter frame; by-ref dispatches into
+ * FETCH_OBJ_W. The function JIT may keep values solely in
+ * registers, so we must NOT exit to the VM (stale stack slots).
+ * Inline the by-value path through zend_jit_fetch_obj, which runs
+ * the hook getter inside a helper and keeps all registers live.
+ * The by-ref path has no SIMPLE_GET fast path, so the generic
+ * handler (a full C call, safe under register allocation) is used.
+ * This mirrors the tracing JIT fix for GH-21006 (GH-21369); the
+ * runtime by-ref check is required because the passing mode is
+ * only known once the callee is resolved via namespace fallback.
+ * See GH-22857. */
+ if (!zend_jit_fetch_obj_func_arg(jit, opline, op_array, ssa, ssa_op,
+ op1_info, op1_addr, ce, ce_is_instanceof, on_this, RES_REG_ADDR())) {
+ goto jit_failure;
+ }
+ } else {
+ if (!zend_jit_fetch_obj(&ctx, opline, op_array, ssa, ssa_op,
+ op1_info, op1_addr, 0, ce, ce_is_instanceof, on_this, 0, 0, NULL,
+ RES_REG_ADDR(), IS_UNKNOWN,
+ zend_may_throw(opline, ssa_op, op_array, ssa))) {
+ goto jit_failure;
+ }
}
goto done;
+ case ZEND_FETCH_STATIC_PROP_R:
+ case ZEND_FETCH_STATIC_PROP_IS:
+ case ZEND_FETCH_STATIC_PROP_W:
+ case ZEND_FETCH_STATIC_PROP_RW:
+ case ZEND_FETCH_STATIC_PROP_UNSET:
+ if (!(opline->op1_type == IS_CONST
+ && (opline->op2_type == IS_CONST
+ || (opline->op2_type == IS_UNUSED
+ && ((opline->op2.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF
+ || (opline->op2.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT))))) {
+ break;
+ }
+ if (!zend_jit_fetch_static_prop(&ctx, opline, op_array)) {
+ goto jit_failure;
+ }
+ goto done;
case ZEND_BIND_GLOBAL:
if (!ssa->ops || !ssa->var_info) {
op1_info = MAY_BE_ANY|MAY_BE_REF;