Skip to content

Commit a165f1f

Browse files
committed
Merge branch 'PHP-8.4'
* PHP-8.4: Fix GH-15169: stack overflow when var serialization in ext/standard/var
2 parents 3f913c1 + 577eb68 commit a165f1f

File tree

4 files changed

+49
-28
lines changed

4 files changed

+49
-28
lines changed

Zend/tests/stack_limit/stack_limit_001.phpt

-14
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,6 @@ class Test2 {
2727
}
2828
}
2929

30-
class Test3 {
31-
public function __sleep()
32-
{
33-
serialize($this);
34-
}
35-
}
36-
3730
function replace() {
3831
return preg_replace_callback('#.#', function () {
3932
return replace();
@@ -52,12 +45,6 @@ try {
5245
echo $e->getMessage(), "\n";
5346
}
5447

55-
try {
56-
serialize(new Test3);
57-
} catch (Error $e) {
58-
echo $e->getMessage(), "\n";
59-
}
60-
6148
try {
6249
replace();
6350
} catch (Error $e) {
@@ -79,4 +66,3 @@ array(4) {
7966
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
8067
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
8168
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
82-
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?

Zend/tests/stack_limit/stack_limit_002.phpt

-14
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@ class Test2 {
2525
}
2626
}
2727

28-
class Test3 {
29-
public function __sleep()
30-
{
31-
serialize($this);
32-
}
33-
}
34-
3528
function replace() {
3629
return preg_replace_callback('#.#', function () {
3730
return replace();
@@ -51,12 +44,6 @@ $fiber = new Fiber(function (): void {
5144
echo $e->getMessage(), "\n";
5245
}
5346

54-
try {
55-
serialize(new Test3);
56-
} catch (Error $e) {
57-
echo $e->getMessage(), "\n";
58-
}
59-
6047
try {
6148
replace();
6249
} catch (Error $e) {
@@ -81,4 +68,3 @@ array(4) {
8168
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
8269
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
8370
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
84-
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
GH-15169 (stack overflow when var serialization in ext/standard/var)
3+
--SKIPIF--
4+
<?php
5+
if (ini_get('zend.max_allowed_stack_size') === false) {
6+
die('skip No stack limit support');
7+
}
8+
if (getenv('SKIP_ASAN')) {
9+
die('skip ASAN needs different stack limit setting due to more stack space usage');
10+
}
11+
?>
12+
--INI--
13+
zend.max_allowed_stack_size=512K
14+
--FILE--
15+
<?php
16+
class Node
17+
{
18+
public $next;
19+
}
20+
$firstNode = new Node();
21+
$node = $firstNode;
22+
for ($i = 0; $i < 30000; $i++) {
23+
$newNode = new Node();
24+
$node->next = $newNode;
25+
$node = $newNode;
26+
}
27+
28+
try {
29+
serialize($firstNode);
30+
} catch (Error $e) {
31+
echo $e->getMessage(), "\n";
32+
}
33+
?>
34+
--EXPECT--
35+
Maximum call stack size reached. Infinite recursion?

ext/standard/var.c

+14
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,15 @@ static void php_var_serialize_class(smart_str *buf, zval *struc, HashTable *ht,
10331033
}
10341034
/* }}} */
10351035

1036+
static zend_always_inline bool php_serialize_check_stack_limit(void)
1037+
{
1038+
#ifdef ZEND_CHECK_STACK_LIMIT
1039+
return zend_call_stack_overflowed(EG(stack_limit));
1040+
#else
1041+
return false;
1042+
#endif
1043+
}
1044+
10361045
static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_data_t var_hash, bool in_rcn_array, bool is_root) /* {{{ */
10371046
{
10381047
zend_long var_already;
@@ -1042,6 +1051,11 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_
10421051
return;
10431052
}
10441053

1054+
if (UNEXPECTED(php_serialize_check_stack_limit())) {
1055+
zend_throw_error(NULL, "Maximum call stack size reached. Infinite recursion?");
1056+
return;
1057+
}
1058+
10451059
if (var_hash && (var_already = php_add_var_hash(var_hash, struc, in_rcn_array))) {
10461060
if (var_already == -1) {
10471061
/* Reference to an object that failed to serialize, replace with null. */

0 commit comments

Comments
 (0)