mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Fix GH-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. Closes GH-16159.
This commit is contained in:
parent
220c8828cc
commit
bd724bdf42
5 changed files with 51 additions and 28 deletions
2
NEWS
2
NEWS
|
@ -56,6 +56,8 @@ PHP NEWS
|
|||
|
||||
- Standard:
|
||||
. Fixed bug GH-16053 (Assertion failure in Zend/zend_hash.c). (Arnaud)
|
||||
. Fixed bug GH-15169 (stack overflow when var serialization in
|
||||
ext/standard/var). (nielsdos)
|
||||
|
||||
- Streams:
|
||||
. Fixed bugs GH-15908 and GH-15026 (leak / assertion failure in streams.c).
|
||||
|
|
|
@ -27,13 +27,6 @@ class Test2 {
|
|||
}
|
||||
}
|
||||
|
||||
class Test3 {
|
||||
public function __sleep()
|
||||
{
|
||||
serialize($this);
|
||||
}
|
||||
}
|
||||
|
||||
function replace() {
|
||||
return preg_replace_callback('#.#', function () {
|
||||
return replace();
|
||||
|
@ -52,12 +45,6 @@ try {
|
|||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
serialize(new Test3);
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
replace();
|
||||
} catch (Error $e) {
|
||||
|
@ -79,4 +66,3 @@ array(4) {
|
|||
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
|
||||
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
|
||||
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
|
||||
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
|
||||
|
|
|
@ -26,13 +26,6 @@ class Test2 {
|
|||
}
|
||||
}
|
||||
|
||||
class Test3 {
|
||||
public function __sleep()
|
||||
{
|
||||
serialize($this);
|
||||
}
|
||||
}
|
||||
|
||||
function replace() {
|
||||
return preg_replace_callback('#.#', function () {
|
||||
return replace();
|
||||
|
@ -52,12 +45,6 @@ $fiber = new Fiber(function (): void {
|
|||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
serialize(new Test3);
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
replace();
|
||||
} catch (Error $e) {
|
||||
|
@ -82,4 +69,3 @@ array(4) {
|
|||
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
|
||||
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
|
||||
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
|
||||
Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
|
||||
|
|
35
ext/standard/tests/serialize/gh15169.phpt
Normal file
35
ext/standard/tests/serialize/gh15169.phpt
Normal file
|
@ -0,0 +1,35 @@
|
|||
--TEST--
|
||||
GH-15169 (stack overflow when var serialization in ext/standard/var)
|
||||
--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=512K
|
||||
--FILE--
|
||||
<?php
|
||||
class Node
|
||||
{
|
||||
public $next;
|
||||
}
|
||||
$firstNode = new Node();
|
||||
$node = $firstNode;
|
||||
for ($i = 0; $i < 30000; $i++) {
|
||||
$newNode = new Node();
|
||||
$node->next = $newNode;
|
||||
$node = $newNode;
|
||||
}
|
||||
|
||||
try {
|
||||
serialize($firstNode);
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Maximum call stack size reached. Infinite recursion?
|
|
@ -986,6 +986,15 @@ static void php_var_serialize_class(smart_str *buf, zval *struc, HashTable *ht,
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
static zend_always_inline bool php_serialize_check_stack_limit(void)
|
||||
{
|
||||
#ifdef ZEND_CHECK_STACK_LIMIT
|
||||
return zend_call_stack_overflowed(EG(stack_limit));
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_data_t var_hash, bool in_rcn_array, bool is_root) /* {{{ */
|
||||
{
|
||||
zend_long var_already;
|
||||
|
@ -995,6 +1004,11 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_
|
|||
return;
|
||||
}
|
||||
|
||||
if (UNEXPECTED(php_serialize_check_stack_limit())) {
|
||||
zend_throw_error(NULL, "Maximum call stack size reached. Infinite recursion?");
|
||||
return;
|
||||
}
|
||||
|
||||
if (var_hash && (var_already = php_add_var_hash(var_hash, struc, in_rcn_array))) {
|
||||
if (var_already == -1) {
|
||||
/* Reference to an object that failed to serialize, replace with null. */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue