Commit 9afb81f60c4 for php
commit 9afb81f60c41201a0c976611a481da9c4eec2385
Author: ndossche <7771979+ndossche@users.noreply.github.com>
Date: Sun Nov 8 15:22:01 2026 +0100
Fix GH-25314: Assertion in ZEND_DO_FCALL: reference returned by &__get() reaches property hook TMP result
Caused by VAR|TMP overhaul.
Closes GH-25317.
diff --git a/NEWS b/NEWS
index 943c2a8de9f..7018b13c075 100644
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,8 @@ PHP NEWS
cached). (lazerg)
. Fixed bug GH-25265 (Misaligned read for virtual internal props in
hooked subclass). (Lazizbek Ergashev)
+ . Fixed bug GH-25314 (Assertion in ZEND_DO_FCALL: reference returned by
+ &__get() reaches property hook TMP result). (ndossche)
- Curl:
. Fixed curl_reset() retaining CURLOPT_PRIVATE after reset. (lacatoire)
diff --git a/Zend/tests/property_hooks/gh25314.phpt b/Zend/tests/property_hooks/gh25314.phpt
new file mode 100644
index 00000000000..a72bef2d9fb
--- /dev/null
+++ b/Zend/tests/property_hooks/gh25314.phpt
@@ -0,0 +1,31 @@
+--TEST--
+GH-25314 (Assertion in ZEND_DO_FCALL: reference returned by &__get() reaches property hook TMP result)
+--CREDITS--
+YuanchengJiang
+--FILE--
+<?php
+
+class P {
+ public int $d = 1;
+ function &__get($name) {}
+}
+class C extends P {
+ public int $d = 2 { get => parent::$d::get(); }
+}
+class GC extends C {
+ public int $d { get => parent::$d::get(); }
+}
+
+var_dump((new GC)->d);
+
+?>
+--EXPECTF--
+Notice: Only variable references should be returned by reference in %s on line %d
+
+Fatal error: Uncaught TypeError: Value of type null returned from GC::__get() must be compatible with unset property GC::$d of type int in %s:%d
+Stack trace:
+#0 %s(%d): P->$d::get()
+#1 %s(%d): C->$d::get()
+#2 %s(%d): GC->$d::get()
+#3 {main}
+ thrown in %s on line %d
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index 5bc9e4004eb..a537f6b2a3e 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -1880,11 +1880,15 @@ static ZEND_FUNCTION(zend_parent_hook_get_trampoline)
}
zval rv;
- const zval *retval = obj->handlers->read_property(obj, prop_name, BP_VAR_R, NULL, &rv);
+ zval *retval = obj->handlers->read_property(obj, prop_name, BP_VAR_R, NULL, &rv);
if (retval == &rv) {
RETVAL_COPY_VALUE(retval);
+ if (UNEXPECTED(Z_ISREF_P(return_value))) {
+ /* __get() may return by reference. */
+ zend_unwrap_reference(return_value);
+ }
} else {
- RETVAL_COPY(retval);
+ RETVAL_COPY_DEREF(retval);
}
clean: