Commit a480965c90b for php.net

commit a480965c90b4f4948f211c8b139788371e031838
Author: Weilin Du <weilindu@php.net>
Date:   Wed Jun 17 04:48:17 2026 +0800

    ext/opcache: unwrap reference wrappers in typed by-value returns (#21973)

diff --git a/NEWS b/NEWS
index 05bdd1b35ff..afb45fca45c 100644
--- a/NEWS
+++ b/NEWS
@@ -93,6 +93,8 @@ PHP                                                                        NEWS
   . Fix persistent free of non-persistent connect_attr key (David Carlier).

 - Opcache:
+  . Fixed bug GH-21972 (Corrupted variable type when a typed by-value return
+    contains a reference wrapper). (Weilin Du)
   . Fixed tracing JIT crash when a VM interrupt is handled during an observed
     user function call. (Levi Morrison)
   . Fixed bug GH-22004 (Assertion failure at ext/opcache/jit/zend_jit_trace.c).
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 34906e1bfcc..c46b1710154 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -4387,7 +4387,7 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV
 			ZVAL_DEREF(retval_ptr);
 		}

-		if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(ret_info->type, Z_TYPE_P(retval_ptr)))) {
+		if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(ret_info->type, Z_TYPE_P(retval_ref)))) {
 			ZEND_VM_NEXT_OPCODE();
 		}

@@ -4417,6 +4417,9 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV
 				}
 				retval_ptr = retval_ref;
 			}
+			if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(ret_info->type, Z_TYPE_P(retval_ptr)))) {
+				ZEND_VM_NEXT_OPCODE();
+			}
 		}

 		SAVE_OPLINE();
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index d4b2aff1907..f4f35ce2a8a 100644
Binary files a/Zend/zend_vm_execute.h and b/Zend/zend_vm_execute.h differ
diff --git a/ext/opcache/tests/opt/gh21972.phpt b/ext/opcache/tests/opt/gh21972.phpt
new file mode 100644
index 00000000000..f34f9b45ccf
--- /dev/null
+++ b/ext/opcache/tests/opt/gh21972.phpt
@@ -0,0 +1,39 @@
+--TEST--
+GH-21972: Typed by-value return must not leak reference wrapper
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+--EXTENSIONS--
+opcache
+--FILE--
+<?php
+declare(strict_types=1);
+
+enum ValueType {
+	case BOOL;
+	case MIXED;
+}
+
+function applyDefinition(
+	bool &$lazy = false,
+	ValueType &$type = ValueType::MIXED,
+	int &$flags = 0,
+	?string &$default = null,
+): void {
+}
+
+function getTypedValue(string $default, bool $lazy, ValueType $type): string {
+	applyDefinition($lazy, $type, default: $default);
+	return $default;
+}
+
+$value = getTypedValue('false', false, ValueType::BOOL);
+var_dump(gettype($value));
+var_dump(strtolower($value));
+var_dump(strtolower(getTypedValue('FALSE', false, ValueType::BOOL)));
+?>
+--EXPECT--
+string(6) "string"
+string(5) "false"
+string(5) "false"