diff --git a/Zend/zend.c b/Zend/zend.c index 17bc4ba0cbad..2ba34831d6e6 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -546,6 +546,12 @@ ZEND_API void zend_print_flat_zval_r(zval *expr) static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /* {{{ */ { +#ifdef ZEND_CHECK_STACK_LIMIT + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { + zend_call_stack_size_error(); + return; + } +#endif switch (Z_TYPE_P(expr)) { case IS_ARRAY: smart_str_appends(buf, "Array\n"); diff --git a/ext/standard/tests/general_functions/gh24605_stack_guard.phpt b/ext/standard/tests/general_functions/gh24605_stack_guard.phpt new file mode 100644 index 000000000000..c86d86bc7a02 --- /dev/null +++ b/ext/standard/tests/general_functions/gh24605_stack_guard.phpt @@ -0,0 +1,42 @@ +--TEST-- +GH-24605 (var_export(), print_r() and unserialize() segfault on deep nesting) +--SKIPIF-- + +--INI-- +zend.max_allowed_stack_size=512K +--FILE-- + static fn() => var_export($a), + 'print_r' => static fn() => print_r($a, true), + 'unserialize' => static fn() => unserialize($u), +]; + +foreach ($calls as $name => $call) { + try { + $call(); + echo $name, ": no error\n"; + } catch (\Error $e) { + echo $name, ': ', + str_contains($e->getMessage(), 'Maximum call stack size') ? 'stack error' : 'other error', + "\n"; + } +} +?> +--EXPECT-- +var_export: stack error +print_r: stack error +unserialize: stack error \ No newline at end of file diff --git a/ext/standard/var.c b/ext/standard/var.c index 6d8fff970b2b..f50c82d72d84 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -538,6 +538,12 @@ static zend_result php_object_element_export(zval *zv, zend_ulong index, zend_st PHPAPI zend_result php_var_export_ex(zval *struc, int level, smart_str *buf) /* {{{ */ { +#ifdef ZEND_CHECK_STACK_LIMIT + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { + zend_call_stack_size_error(); + return FAILURE; + } +#endif HashTable *myht; zend_string *ztmp, *ztmp2; zend_ulong index; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 51c3293c63e2..89c6d5466e21 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -937,6 +937,12 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) { +#ifdef ZEND_CHECK_STACK_LIMIT + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { + zend_call_stack_size_error(); + return 0; + } +#endif const unsigned char *cursor, *limit, *marker, *start; zval *rval_ref;