diff --git a/Zend/tests/exceptions/exception_fatal_uncaught_error_reference_tostring.phpt b/Zend/tests/exceptions/exception_fatal_uncaught_error_reference_tostring.phpt new file mode 100644 index 0000000000000..6222a0895baf2 --- /dev/null +++ b/Zend/tests/exceptions/exception_fatal_uncaught_error_reference_tostring.phpt @@ -0,0 +1,19 @@ +--TEST-- +Exception fatal uncaught error with reference __toString +--FILE-- +field; + } +} + +// Must not be caught to trigger the issue! +throw new MyException; + +?> +--EXPECTF-- +Fatal error: Uncaught my string + thrown in %s on line %d diff --git a/Zend/tests/type_casts/string_cast_reference_tostring.phpt b/Zend/tests/type_casts/string_cast_reference_tostring.phpt new file mode 100644 index 0000000000000..96b47a4fba9bc --- /dev/null +++ b/Zend/tests/type_casts/string_cast_reference_tostring.phpt @@ -0,0 +1,17 @@ +--TEST-- +String cast with reference __toString +--FILE-- +field; + } +} + +echo new MyClass; + +?> +--EXPECT-- +my string diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 7777c5fa62e48..c3910ed7c19fd 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -980,6 +980,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 { diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index f79023ade1c25..7b804e7afe95a 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -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)) { diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 92c139fa52abe..84bd7a076acec 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -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));