[php-src] master: Merge branch 'PHP-8.4' into PHP-8.5

From: Date: Mon, 10 Aug 2026 10:03:05 +0000
Subject: [php-src] master: Merge branch 'PHP-8.4' into PHP-8.5
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-140581@lists.php.net to get a copy of this message
Author: Arnaud Le Blanc (arnaud-lb) Date: 2026-08-10T12:01:05+02:00 Commit: https://github.com/php/php-src/commit/5ae3f54aa3636b1a547d3b0484a5f75929552dd0 Raw diff: https://github.com/php/php-src/commit/5ae3f54aa3636b1a547d3b0484a5f75929552dd0.diff Merge branch 'PHP-8.4' into PHP-8.5 * PHP-8.4: Add a stack limit check in php_array_replace_recursive (#23124) Add a stack limit check in php_array_walk() (#23125) Changed paths: A ext/standard/tests/array/gh23111.phpt A ext/standard/tests/array/gh23113.phpt M NEWS M ext/standard/array.c Diff: diff --git a/NEWS b/NEWS index 72388b5c946b..9cdb2f782101 100644 --- a/NEWS +++ b/NEWS @@ -76,6 +76,12 @@ PHP NEWS - SQLite: . Fix leak when trying to close db if blob stream is still open. (ndossche) +- Standard: + . Fixed bug GH-23111 (Stack overflow in array_walk_recursive() with deeply + nested arrays). (Lazizbek Ergashev) + . Fixed bug GH-23113 (Stack overflow in array_replace_recursive() with deeply + nested arrays). (Lazizbek Ergashev) + - Streams: . Fixed bug GH-15836 (Use-after-free when a user stream filter accesses $this->stream during the close flush). (iliaal) diff --git a/ext/standard/array.c b/ext/standard/array.c index bb5f43e405ea..79ff4c8c4923 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -1450,6 +1450,13 @@ static zend_result php_array_walk( * levels of recursion. */ zend_fcall_info fci = context->fci; +#ifdef ZEND_CHECK_STACK_LIMIT + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { + zend_call_stack_size_error(); + return FAILURE; + } +#endif + if (zend_hash_num_elements(target_hash) == 0) { return result; } @@ -4152,6 +4159,13 @@ PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src) /* {{{ * zend_ulong num_key; int ret; +#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_KEY_VAL(src, num_key, string_key, src_entry) { src_zval = src_entry; ZVAL_DEREF(src_zval); diff --git a/ext/standard/tests/array/gh23111.phpt b/ext/standard/tests/array/gh23111.phpt new file mode 100644 index 000000000000..21db33a2fc75 --- /dev/null +++ b/ext/standard/tests/array/gh23111.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-23111 (Stack overflow in array_walk_recursive with deeply nested arrays) +--SKIPIF-- +<?php +if (ini_get('zend.max_allowed_stack_size') === false) { + die('skip No stack limit support'); +} +if (getenv('SKIP_ASAN')) { + die('skip ASAN needs different stack limit setting due to more stack space usage'); +} +?> +--INI-- +zend.max_allowed_stack_size=256K +--FILE-- +<?php +$a = []; +for ($i = 0; $i < 30000; $i++) { + $a = [$a]; +} +try { + array_walk_recursive($a, function ($v) {}); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} +?> +--EXPECTF-- +Error: Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion? diff --git a/ext/standard/tests/array/gh23113.phpt b/ext/standard/tests/array/gh23113.phpt new file mode 100644 index 000000000000..894e8d971e53 --- /dev/null +++ b/ext/standard/tests/array/gh23113.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-23113 (Stack overflow in array_replace_recursive with deeply nested arrays) +--SKIPIF-- +<?php +if (ini_get('zend.max_allowed_stack_size') === false) { + die('skip No stack limit support'); +} +if (getenv('SKIP_ASAN')) { + die('skip ASAN needs different stack limit setting due to more stack space usage'); +} +?> +--INI-- +zend.max_allowed_stack_size=256K +--FILE-- +<?php +$a = []; +for ($i = 0; $i < 30000; $i++) { + $a = ['k' => $a]; +} +try { + array_replace_recursive($a, $a); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} +?> +--EXPECTF-- +Error: Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?

« previous php.cvs (#140581) next »