diff --git a/Zend/tests/property_hooks/gh25314.phpt b/Zend/tests/property_hooks/gh25314.phpt new file mode 100644 index 000000000000..a72bef2d9fb9 --- /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-- + 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 5bc9e4004eb8..a537f6b2a3ea 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: