diff --git a/NEWS b/NEWS index 18b784ca064c..01f372ab14a5 100644 --- a/NEWS +++ b/NEWS @@ -86,6 +86,8 @@ PHP NEWS (ndossche) - Standard: + . Fixed bug GH-23089 (Stack overflow in array_merge_recursive() with deeply + nested arrays). (Lazizbek Ergashev, akasakariko) . Fixed dns_get_record() returning partially built records for malformed DNS responses. (Marti2203) diff --git a/ext/standard/array.c b/ext/standard/array.c index c10ad47c093f..9e308ca528f2 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -4100,6 +4100,13 @@ PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src) /* {{{ */ zval *src_entry, *dest_entry; zend_string *string_key; +#ifdef ZEND_CHECK_STACK_LIMIT + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { + zend_call_stack_size_error(); + return 0; + } +#endif + ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) { if (string_key) { if ((dest_entry = zend_hash_find_known_hash(dest, string_key)) != NULL) { diff --git a/ext/standard/tests/array/gh23089.phpt b/ext/standard/tests/array/gh23089.phpt new file mode 100644 index 000000000000..85ba69484450 --- /dev/null +++ b/ext/standard/tests/array/gh23089.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-23089 (Stack overflow in array_merge_recursive with deeply nested arrays) +--SKIPIF-- + +--INI-- +zend.max_allowed_stack_size=1M +--FILE-- + $a]; +} +try { + array_merge_recursive($a, $a); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +/* Avoid the separate stack overflow during array destruction (GH-15869). */ +unset($e); +while ($a) { + $a = $a['k']; +} +?> +--EXPECTF-- +Error: Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?