Commit f0301f3ca2e for php

commit f0301f3ca2e2e278aa1b8d33de60f87c6a359337
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date:   Sun Oct 11 04:30:22 2026 -0400

    ext/opcache: Do not reuse the assigned range through typed references (#24210)

    An assignment through a reference to a typed property coerces the value, so
    its result can differ from the assigned operand, but range inference copied
    the operand's range to the result. Reuse it only when the target is a CV
    that cannot be a reference.

diff --git a/NEWS b/NEWS
index 9c5f7bede78..44fb719c698 100644
--- a/NEWS
+++ b/NEWS
@@ -54,6 +54,8 @@ PHP                                                                        NEWS
   . Fixed field_count not resetting on OK packet. (Kamil Tekiela)

 - Opcache:
+  . Fixed range inference of assignments through typed references.
+    (Ilia Alshanetsky)
   . Fixed bug GH-23693 (Tracing JIT produces wrong results for a guard on a
     loop-invariant addition). (Ilia Alshanetsky)
   . Fixed OSS-Fuzz #545352966 (default value AST of an SHM-persisted partial).
diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c
index 2e210414c30..effff75e00f 100644
--- a/Zend/Optimizer/zend_inference.c
+++ b/Zend/Optimizer/zend_inference.c
@@ -1445,7 +1445,9 @@ ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, cons
 			break;
 		case ZEND_ASSIGN:
 			if (ssa_op->op1_def == var || ssa_op->op2_def == var || ssa_op->result_def == var) {
-				if (OP2_HAS_RANGE()) {
+				if (OP2_HAS_RANGE()
+				 && (ssa_op->op2_def == var
+				  || (opline->op1_type == IS_CV && !(OP1_INFO() & MAY_BE_REF)))) {
 					tmp->min = OP2_MIN_RANGE();
 					tmp->max = OP2_MAX_RANGE();
 					tmp->underflow = OP2_RANGE_UNDERFLOW();
diff --git a/ext/opcache/tests/opt/assign_typed_ref_range.phpt b/ext/opcache/tests/opt/assign_typed_ref_range.phpt
new file mode 100644
index 00000000000..5cd7b1ed4f2
--- /dev/null
+++ b/ext/opcache/tests/opt/assign_typed_ref_range.phpt
@@ -0,0 +1,59 @@
+--TEST--
+Assignment through typed references must not reuse the assigned range
+--EXTENSIONS--
+opcache
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+error_reporting=E_ALL & ~E_DEPRECATED
+--FILE--
+<?php
+class Box {
+    public int $value = 0;
+}
+
+function assignBounded(&$reference, $value) {
+    if ($value > 5 && $value < 7) {
+        $result = ($reference = $value);
+        if (is_int($result)) {
+            return $result;
+        }
+    }
+}
+
+function assignEqual(&$reference, $value) {
+    if ($value == 6) {
+        $result = ($reference = $value);
+        if (is_int($result)) {
+            return $result;
+        }
+    }
+}
+
+function assignGlobal($value) {
+    if ($value > 5 && $value < 7) {
+        $result = ($GLOBALS['reference'] = $value);
+        if (is_int($result)) {
+            return $result;
+        }
+    }
+}
+
+$box = new Box();
+echo 'float: ', assignBounded($box->value, 5.5), ', stored: ', $box->value, "\n";
+echo 'numeric string: ', assignBounded($box->value, '5.5'), ', stored: ', $box->value, "\n";
+echo 'boolean: ', assignEqual($box->value, true), ', stored: ', $box->value, "\n";
+echo 'integer: ', assignBounded($box->value, 6), ', stored: ', $box->value, "\n";
+
+$GLOBALS['reference'] = &$box->value;
+echo 'global float: ', assignGlobal(5.5), ', stored: ', $box->value, "\n";
+echo 'global integer: ', assignGlobal(6), ', stored: ', $box->value, "\n";
+?>
+--EXPECT--
+float: 5, stored: 5
+numeric string: 5, stored: 5
+boolean: 1, stored: 1
+integer: 6, stored: 6
+global float: 5, stored: 5
+global integer: 6, stored: 6
diff --git a/ext/opcache/tests/opt/assign_typed_ref_range_64bit.phpt b/ext/opcache/tests/opt/assign_typed_ref_range_64bit.phpt
new file mode 100644
index 00000000000..8ca387c07b2
--- /dev/null
+++ b/ext/opcache/tests/opt/assign_typed_ref_range_64bit.phpt
@@ -0,0 +1,26 @@
+--TEST--
+Assignment through a float typed reference must not reuse the assigned integer range
+--EXTENSIONS--
+opcache
+--SKIPIF--
+<?php if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only"); ?>
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+--FILE--
+<?php
+class Box {
+    public float $real = 0.0;
+}
+
+function assignGlobalFloat() {
+    return ($GLOBALS['real'] = 9007199254740993) & 1;
+}
+
+$box = new Box();
+$GLOBALS['real'] = &$box->real;
+var_dump(assignGlobalFloat());
+?>
+--EXPECT--
+int(0)