Skip to content

Commit 48b8d8c

Browse files
committed
Fix phpGH-15169: stack overflow when var serialization in ext/standard/var
Adding a stack check here as I consider serialization to be a more sensitive place where erroring out with an exception seems appropriate.
1 parent 4a16940 commit 48b8d8c

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed
+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
@@ -986,6 +986,15 @@ static void php_var_serialize_class(smart_str *buf, zval *struc, HashTable *ht,
986986
}
987987
/* }}} */
988988

989+
static zend_always_inline bool php_serialize_check_stack_limit(void)
990+
{
991+
#ifdef ZEND_CHECK_STACK_LIMIT
992+
return zend_call_stack_overflowed(EG(stack_limit));
993+
#else
994+
return false;
995+
#endif
996+
}
997+
989998
static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_data_t var_hash, bool in_rcn_array, bool is_root) /* {{{ */
990999
{
9911000
zend_long var_already;
@@ -995,6 +1004,11 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_
9951004
return;
9961005
}
9971006

1007+
if (UNEXPECTED(php_serialize_check_stack_limit())) {
1008+
zend_throw_error(NULL, "Maximum call stack size reached. Infinite recursion?");
1009+
return;
1010+
}
1011+
9981012
if (var_hash && (var_already = php_add_var_hash(var_hash, struc, in_rcn_array))) {
9991013
if (var_already == -1) {
10001014
/* Reference to an object that failed to serialize, replace with null. */

0 commit comments

Comments
 (0)