Skip to content

print_r should not produce a fatal error #7922

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
mvorisek opened this issue Jan 10, 2022 · 4 comments
Open

print_r should not produce a fatal error #7922

mvorisek opened this issue Jan 10, 2022 · 4 comments

Comments

@mvorisek
Copy link
Contributor

Description

print_r (and any function calling __debugInfo()) should not produce a fatal error, it should generate an \Error exception instead

demo https://3v4l.org/YTfSl

@cmb69
Copy link
Member

cmb69 commented Jan 10, 2022

Yeah, that zend_error_noreturn() looks overly strict, especially since return NULL would be accepted and properly handled. We could treat other return types likely like NULL:

 Zend/zend_object_handlers.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index 28d0077878..f1e3c46299 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -150,7 +150,8 @@ ZEND_API HashTable *zend_std_get_debug_info(zend_object *object, int *is_temp) /
 	}
 
 	zend_call_known_instance_method_with_0_params(ce->__debugInfo, object, &retval);
-	if (Z_TYPE(retval) == IS_ARRAY) {
+	switch (Z_TYPE(retval)) {
+		case IS_ARRAY:
 		if (!Z_REFCOUNTED(retval)) {
 			*is_temp = 1;
 			return zend_array_dup(Z_ARRVAL(retval));
@@ -163,14 +164,15 @@ ZEND_API HashTable *zend_std_get_debug_info(zend_object *object, int *is_temp) /
 			zval_ptr_dtor(&retval);
 			return Z_ARRVAL(retval);
 		}
-	} else if (Z_TYPE(retval) == IS_NULL) {
+		default:
+		zend_throw_error(NULL, ZEND_DEBUGINFO_FUNC_NAME "() must return an array");
+		/* fallthrough */
+		case IS_NULL:
 		*is_temp = 1;
 		ht = zend_new_array(0);
 		return ht;
 	}
 
-	zend_error_noreturn(E_ERROR, ZEND_DEBUGINFO_FUNC_NAME "() must return an array");
-
 	return NULL; /* Compilers are dumb and don't understand that noreturn means that the function does NOT need a return value... */
 }
 /* }}} */

(improper indentation to simply the diff)

@TysonAndre
Copy link
Contributor

In addition to throwing, I think you'd need to call zval_ptr_dtor to free incorrect return values of type strings/objects/resources from __debugInfo but it seems reasonable otherwise

cmb69 added a commit to cmb69/php-src that referenced this issue Jan 18, 2022
Fataling if `::__debugInfo()` doesn't return an array appears to be
overly restrictive; we can handle that like returning null, namely by
throwing an `Error` exception and returning an empty array instead.
@cmb69 cmb69 linked a pull request Jan 18, 2022 that will close this issue
mvorisek pushed a commit to mvorisek/php-src that referenced this issue Jun 25, 2022
Fataling if `::__debugInfo()` doesn't return an array appears to be
overly restrictive; we can handle that like returning null, namely by
throwing an `Error` exception and returning an empty array instead.
@flack
Copy link

flack commented Jun 28, 2022

I've recently encountered what I think is a manifestation of this bug:

class test
{
    public function __debugInfo()
    {
        throw new Exception('X');
    }
}

function error(test $object)
{
    throw new Exception('X');
}

try {
    error(new test);
} catch (Exception $e) {
    echo 'All is well';
}

When you run this on standard PHP, it'll print All is well. But when you have XDebug enabled, you'll get something like:

PHP Warning:  Uncaught Exception: X in test.php:5
Stack trace:
#0 test.php(11): test->__debugInfo()
#1 test.php(15): error()
#2 {main}
  thrown in test.php on line 5
PHP Stack trace:
PHP   1. {main}() test.php:0
PHP   2. error($object = class test {  }) test.php:14
PHP Fatal error:  __debuginfo() must return an array in test.php on line 11
PHP Stack trace:
PHP   1. {main}() test.php:0
PHP   2. error($object = class test {  }) test.php:15

I'm not sure, but my guess is that when the Exception is created, XDebug tries to augment the backtrace by adding the arguments, which internally calls var_dump or similar, which then triggers a fatal error. So you can have code that works flawlessly in a production environment, but it breaks when you're trying to debug it

@mvorisek
Copy link
Contributor Author

print_r might be a good candidate for plain php impl. once #18204 is merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants