diff --git a/Zend/tests/debug_info-error-0.0.phpt b/Zend/tests/debug_info-error-0.0.phpt index e3996e0f25996..fdcdf30a9b747 100644 --- a/Zend/tests/debug_info-error-0.0.phpt +++ b/Zend/tests/debug_info-error-0.0.phpt @@ -17,4 +17,8 @@ $c = new C(0.0); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-0.0.php on line %d +Fatal error: Uncaught Error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-0.0.php:14 +Stack trace: +#0 %s(14): var_dump(Object(C)) +#1 {main} + thrown in %s on line 14 diff --git a/Zend/tests/debug_info-error-0.phpt b/Zend/tests/debug_info-error-0.phpt index 7dbac320a1754..2aef18b69c7a4 100644 --- a/Zend/tests/debug_info-error-0.phpt +++ b/Zend/tests/debug_info-error-0.phpt @@ -17,4 +17,8 @@ $c = new C(0); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-0.php on line %d +Fatal error: Uncaught Error: __debuginfo() must return an array in %s:%d +Stack trace: +#0 %s(14): var_dump(Object(C)) +#1 {main} + thrown in %s on line 14 diff --git a/Zend/tests/debug_info-error-1.0.phpt b/Zend/tests/debug_info-error-1.0.phpt index 0213e9daad250..08c092fb4169f 100644 --- a/Zend/tests/debug_info-error-1.0.phpt +++ b/Zend/tests/debug_info-error-1.0.phpt @@ -17,4 +17,8 @@ $c = new C(1.0); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-1.0.php on line %d +Fatal error: Uncaught Error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-1.0.php:14 +Stack trace: +#0 %s(14): var_dump(Object(C)) +#1 {main} + thrown in %s on line 14 diff --git a/Zend/tests/debug_info-error-1.phpt b/Zend/tests/debug_info-error-1.phpt index a8e4644b49083..3c023911c08d8 100644 --- a/Zend/tests/debug_info-error-1.phpt +++ b/Zend/tests/debug_info-error-1.phpt @@ -17,4 +17,8 @@ $c = new C(1); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-1.php on line %d +Fatal error: Uncaught Error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-1.php:14 +Stack trace: +#0 %s(14): var_dump(Object(C)) +#1 {main} + thrown in %s on line 14 diff --git a/Zend/tests/debug_info-error-empty_str.phpt b/Zend/tests/debug_info-error-empty_str.phpt index 39f227cb96750..3553864bec760 100644 --- a/Zend/tests/debug_info-error-empty_str.phpt +++ b/Zend/tests/debug_info-error-empty_str.phpt @@ -17,4 +17,8 @@ $c = new C(""); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-empty_str.php on line %d +Fatal error: Uncaught Error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-empty_str.php:14 +Stack trace: +#0 %s(14): var_dump(Object(C)) +#1 {main} + thrown in %s on line 14 diff --git a/Zend/tests/debug_info-error-false.phpt b/Zend/tests/debug_info-error-false.phpt index bf18ed4d038d8..79ad1ebf8b709 100644 --- a/Zend/tests/debug_info-error-false.phpt +++ b/Zend/tests/debug_info-error-false.phpt @@ -17,4 +17,8 @@ $c = new C(false); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-false.php on line %d +Fatal error: Uncaught Error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-false.php:14 +Stack trace: +#0 %s(14): var_dump(Object(C)) +#1 {main} + thrown in %s on line 14 diff --git a/Zend/tests/debug_info-error-object.phpt b/Zend/tests/debug_info-error-object.phpt index e94c2dfb36ccb..de2b337d470a1 100644 --- a/Zend/tests/debug_info-error-object.phpt +++ b/Zend/tests/debug_info-error-object.phpt @@ -17,4 +17,8 @@ $c = new C(new stdClass); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-object.php on line %d +Fatal error: Uncaught Error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-object.php:14 +Stack trace: +#0 %s(14): var_dump(Object(C)) +#1 {main} + thrown in %s on line 14 diff --git a/Zend/tests/debug_info-error-resource.phpt b/Zend/tests/debug_info-error-resource.phpt index 285ed72e33072..dde17063f452c 100644 --- a/Zend/tests/debug_info-error-resource.phpt +++ b/Zend/tests/debug_info-error-resource.phpt @@ -19,4 +19,8 @@ $c = new C(fopen("data:text/plain,Foo", 'r')); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-resource.php on line %d +Fatal error: Uncaught Error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-resource.php:14 +Stack trace: +#0 %s(14): var_dump(Object(C)) +#1 {main} + thrown in %s on line 14 diff --git a/Zend/tests/debug_info-error-str.phpt b/Zend/tests/debug_info-error-str.phpt index daf0ad3b588ea..1ab731f16205b 100644 --- a/Zend/tests/debug_info-error-str.phpt +++ b/Zend/tests/debug_info-error-str.phpt @@ -17,4 +17,8 @@ $c = new C("foo"); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-str.php on line %d +Fatal error: Uncaught Error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-str.php:14 +Stack trace: +#0 %s(14): var_dump(Object(C)) +#1 {main} + thrown in %s on line 14 diff --git a/Zend/tests/debug_info-error-true.phpt b/Zend/tests/debug_info-error-true.phpt index 41a68c5c3965f..e343e4217cc75 100644 --- a/Zend/tests/debug_info-error-true.phpt +++ b/Zend/tests/debug_info-error-true.phpt @@ -17,4 +17,8 @@ $c = new C(true); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-true.php on line %d +Fatal error: Uncaught Error: __debuginfo() must return an array in %s%eZend%etests%edebug_info-error-true.php:14 +Stack trace: +#0 %s(14): var_dump(Object(C)) +#1 {main} + thrown in %s on line 14 diff --git a/Zend/tests/gh7922.phpt b/Zend/tests/gh7922.phpt new file mode 100644 index 0000000000000..69bb25d53926f --- /dev/null +++ b/Zend/tests/gh7922.phpt @@ -0,0 +1,105 @@ +--TEST-- +GH-7922 (print_r should not produce a fatal error) +--FILE-- + 2]; + } + }); +} catch (\Throwable $e) { + echo $e . "\n"; +} + +echo "\nException occuring later on (print_r):\n"; + +try { + print_r(['foo' => 'bar', 'baz' => new A()]); +} catch (\Throwable $e) { + echo $e . "\n"; +} + +echo "\nException occuring later on (var_dump):\n"; + +try { + var_dump(['u' => 1], ['foo' => 'bar', 'baz' => new A()], ['u' => 1]); +} catch (\Throwable $e) { + echo $e . "\n"; +} + +?> +--EXPECTF-- +Exception in __debugInfo: +Error: x in %s:%d +Stack trace: +#0 [internal function]: A->__debugInfo() +#1 %s(%d): print_r(Object(A)) +#2 {main} + +Exception in __debugInfo in anonymous class: +Exception: y in %s:%d +Stack trace: +#0 [internal function]: A@anonymous->__debugInfo() +#1 %s(%d): print_r(Object(A@anonymous)) +#2 {main} + +Exception in __destruct of __debugInfo in anonymous class: +Exception: z_w_assign in %s:%d +Stack trace: +#0 [internal function]: class@anonymous->__destruct() +#1 %s(%d): print_r(Object(A@anonymous)) +#2 {main} + +Exception occuring later on (print_r): +Error: x in %s:%d +Stack trace: +#0 [internal function]: A->__debugInfo() +#1 %s(%d): print_r(Array) +#2 {main} + +Exception occuring later on (var_dump): +Error: x in %s:%d +Stack trace: +#0 [internal function]: A->__debugInfo() +#1 %s(%d): var_dump(Array) +#2 {main} diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index d767e83997852..5769e02f8d0bd 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -164,27 +164,35 @@ 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) { - if (!Z_REFCOUNTED(retval)) { - *is_temp = 1; - return zend_array_dup(Z_ARRVAL(retval)); - } else if (Z_REFCOUNT(retval) <= 1) { + if (EG(exception)) { + zval_ptr_dtor(&retval); + return NULL; + } + + switch (Z_TYPE(retval)) { + case IS_ARRAY: + if (!Z_REFCOUNTED(retval)) { + *is_temp = 1; + return zend_array_dup(Z_ARRVAL(retval)); + } else if (Z_REFCOUNT(retval) <= 1) { + *is_temp = 1; + ht = Z_ARR(retval); + return ht; + } else { + *is_temp = 0; + zval_ptr_dtor(&retval); + return Z_ARRVAL(retval); + } + case IS_NULL: *is_temp = 1; - ht = Z_ARR(retval); + ht = zend_new_array(0); return ht; - } else { - *is_temp = 0; + default: + zend_throw_error(NULL, ZEND_DEBUGINFO_FUNC_NAME "() must return an array"); zval_ptr_dtor(&retval); - return Z_ARRVAL(retval); - } - } else if (Z_TYPE(retval) == IS_NULL) { - *is_temp = 1; - ht = zend_new_array(0); - return ht; + return NULL; } - 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... */ } /* }}} */ diff --git a/ext/ffi/tests/035.phpt b/ext/ffi/tests/035.phpt index b36f246708143..f09bb101cfd3c 100644 --- a/ext/ffi/tests/035.phpt +++ b/ext/ffi/tests/035.phpt @@ -23,6 +23,4 @@ object(FFI\CData:uint16_t[2])#%d (2) { [1]=> int(0) } -object(FFI\CData:uint16_t[2])#%d (0) { -} FFI\Exception: Use after free() diff --git a/ext/standard/var.c b/ext/standard/var.c index 268c535a80242..e4e8c7f256526 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -161,6 +161,9 @@ PHPAPI void php_var_dump(zval *struc, int level) /* {{{ */ Z_PROTECT_RECURSION_P(struc); myht = zend_get_properties_for(struc, ZEND_PROP_PURPOSE_DEBUG); + if (EG(exception)) { + break; + } class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc)); php_printf("%sobject(%s)#%d (%d) {\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0); zend_string_release_ex(class_name, 0);