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

Arnaud Le Blanc <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Arnaud Le Blanc (arnaud-lb)
Date: 2026-08-10T12:01:23+02:00

Commit: https://github.com/php/php-src/commit/6ff0dcc0664ac92f7616bdfeced76d89790e5928
Raw diff: https://github.com/php/php-src/commit/6ff0dcc0664ac92f7616bdfeced76d89790e5928.diff

Merge branch 'PHP-8.5'

* PHP-8.5:
  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  ext/standard/array.c


Diff:

diff --git a/ext/standard/array.c b/ext/standard/array.c
index 584afada2089..4dc12d0f59cc 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -1385,6 +1385,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;
 	}
@@ -4048,6 +4055,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?
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.