mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Properly handle reference return value from __toString()
It's possible to return a reference from __toString(), but this is not handled and results in a (confusing) error telling that the return value must be a string. Properly handle this by unwrapping the reference. Closes GH-18810.
This commit is contained in:
1
NEWS
1
NEWS
@@ -54,6 +54,7 @@ PHP NEWS
|
||||
released on bailout). (DanielEScherzer and ilutov)
|
||||
. Fixed AST printing for immediately invoked Closure. (Dmitrii Derepko)
|
||||
. Properly handle __debugInfo() returning an array reference. (nielsdos)
|
||||
. Properly handle reference return value from __toString(). (nielsdos)
|
||||
. Added the pipe (|>) operator. (crell)
|
||||
|
||||
- Curl:
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
Exception fatal uncaught error with reference __toString
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class MyException extends Exception {
|
||||
private $field = 'my string';
|
||||
public function &__toString(): string {
|
||||
return $this->field;
|
||||
}
|
||||
}
|
||||
|
||||
// Must not be caught to trigger the issue!
|
||||
throw new MyException;
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught my string
|
||||
thrown in %s on line %d
|
||||
17
Zend/tests/type_casts/string_cast_reference_tostring.phpt
Normal file
17
Zend/tests/type_casts/string_cast_reference_tostring.phpt
Normal file
@@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
String cast with reference __toString
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class MyClass {
|
||||
private $field = 'my string';
|
||||
public function &__toString(): string {
|
||||
return $this->field;
|
||||
}
|
||||
}
|
||||
|
||||
echo new MyClass;
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
my string
|
||||
@@ -969,6 +969,9 @@ ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *ex, int severit
|
||||
|
||||
zend_call_known_instance_method_with_0_params(ex->ce->__tostring, ex, &tmp);
|
||||
if (!EG(exception)) {
|
||||
if (UNEXPECTED(Z_ISREF(tmp))) {
|
||||
zend_unwrap_reference(&tmp);
|
||||
}
|
||||
if (Z_TYPE(tmp) != IS_STRING) {
|
||||
zend_error(E_WARNING, "%s::__toString() must return a string", ZSTR_VAL(ce_exception->name));
|
||||
} else {
|
||||
|
||||
@@ -2440,8 +2440,12 @@ ZEND_API zend_result zend_std_cast_object_tostring(zend_object *readobj, zval *w
|
||||
zend_call_known_instance_method_with_0_params(ce->__tostring, readobj, &retval);
|
||||
zend_object_release(readobj);
|
||||
if (EXPECTED(Z_TYPE(retval) == IS_STRING)) {
|
||||
is_string:
|
||||
ZVAL_COPY_VALUE(writeobj, &retval);
|
||||
return SUCCESS;
|
||||
} else if (Z_ISREF(retval)) {
|
||||
zend_unwrap_reference(&retval);
|
||||
goto is_string;
|
||||
}
|
||||
zval_ptr_dtor(&retval);
|
||||
if (!EG(exception)) {
|
||||
|
||||
@@ -702,6 +702,10 @@ static inline void phpdbg_handle_exception(void) /* {{{ */
|
||||
EG(exception) = NULL;
|
||||
msg = ZSTR_EMPTY_ALLOC();
|
||||
} else {
|
||||
if (UNEXPECTED(Z_ISREF(tmp))) {
|
||||
zend_unwrap_reference(&tmp);
|
||||
}
|
||||
ZEND_ASSERT(Z_TYPE(tmp) == IS_STRING);
|
||||
zend_update_property_string(zend_get_exception_base(ex), ex, ZEND_STRL("string"), Z_STRVAL(tmp));
|
||||
zval_ptr_dtor(&tmp);
|
||||
msg = zval_get_string(zend_read_property_ex(zend_get_exception_base(ex), ex, ZSTR_KNOWN(ZEND_STR_STRING), /* silent */ true, &rv));
|
||||
|
||||
Reference in New Issue
Block a user