Skip to content

Commit bc2d2fc

Browse files
committed
Merge branch 'PHP-8.6'
* PHP-8.6: Fix stack overflow in filter_var() and filter_var_array() (#25349)
2 parents 16ebaff + 13bdad8 commit bc2d2fc

2 files changed

Lines changed: 59 additions & 0 deletions

File tree

‎ext/filter/filter.c‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,13 @@ static void php_zval_filter_recursive(zval *value, zend_long filter, zend_long f
421421
if (Z_TYPE_P(value) == IS_ARRAY) {
422422
zval *element;
423423

424+
#ifdef ZEND_CHECK_STACK_LIMIT
425+
if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) {
426+
zend_call_stack_size_error();
427+
return;
428+
}
429+
#endif
430+
424431
if (Z_IS_RECURSIVE_P(value)) {
425432
return;
426433
}
@@ -431,6 +438,10 @@ static void php_zval_filter_recursive(zval *value, zend_long filter, zend_long f
431438
if (Z_TYPE_P(element) == IS_ARRAY) {
432439
SEPARATE_ARRAY(element);
433440
php_zval_filter_recursive(element, filter, flags, options, charset);
441+
if (EG(exception)) {
442+
Z_UNPROTECT_RECURSION_P(value);
443+
return;
444+
}
434445
} else {
435446
php_zval_filter(element, filter, flags, options, charset);
436447
}
@@ -658,6 +669,7 @@ static void php_filter_array_handler(zval *input, HashTable *op_ht, zend_long op
658669
2
659670
);
660671
if (EG(exception)) {
672+
zval_ptr_dtor(&nval);
661673
RETURN_THROWS();
662674
}
663675
zend_hash_update(Z_ARRVAL_P(return_value), arg_key, &nval);
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
--TEST--
2+
Stack overflow in filter_var() and filter_var_array() with deeply nested arrays
3+
--EXTENSIONS--
4+
filter
5+
--SKIPIF--
6+
<?php
7+
if (ini_get('zend.max_allowed_stack_size') === false) {
8+
die('skip No stack limit support');
9+
}
10+
if (getenv('SKIP_ASAN')) {
11+
die('skip ASAN needs different stack limit setting due to more stack space usage');
12+
}
13+
?>
14+
--INI--
15+
zend.max_allowed_stack_size=256K
16+
--FILE--
17+
<?php
18+
$deep = 'x';
19+
for ($i = 0; $i < 30000; $i++) {
20+
$deep = [$deep];
21+
}
22+
23+
/* Two top-level entries: the second must not be visited once the
24+
* stack limit error has been thrown, so only one Error is thrown. */
25+
try {
26+
filter_var([$deep, $deep], FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
27+
} catch (Error $e) {
28+
echo $e->getMessage(), "\n";
29+
var_dump($e->getPrevious());
30+
}
31+
try {
32+
filter_var_array(['a' => $deep, 'b' => $deep], ['a' => ['flags' => FILTER_REQUIRE_ARRAY], 'b' => ['flags' => FILTER_REQUIRE_ARRAY]]);
33+
} catch (Error $e) {
34+
echo $e->getMessage(), "\n";
35+
var_dump($e->getPrevious());
36+
}
37+
38+
unset($e);
39+
while (is_array($deep)) {
40+
$deep = $deep[0];
41+
}
42+
?>
43+
--EXPECTF--
44+
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
45+
NULL
46+
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
47+
NULL

0 commit comments

Comments
 (0)