mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Fix GH-15168: stack overflow in json_encode()
The JSON encoder is recursive, and it's far from easy to make it iterative. Add a cheap stack limit check to prevent a segfault. This uses the PHP_JSON_ERROR_DEPTH error code that already talks about the stack depth. Previously this was only used for the $depth argument. Closes GH-16059.
This commit is contained in:
3
NEWS
3
NEWS
@@ -15,6 +15,9 @@ PHP NEWS
|
||||
. Fixed bug GH-16039 (Segmentation fault (access null pointer) in
|
||||
ext/dom/parentnode/tree.c). (nielsdos)
|
||||
|
||||
- JSON:
|
||||
. Fixed bug GH-15168 (stack overflow in json_encode()). (nielsdos)
|
||||
|
||||
- LDAP:
|
||||
. Fixed bug GH-16032 (Various NULL pointer dereferencements in
|
||||
ldap_modify_batch()). (Girgias)
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
|
||||
static const char digits[] = "0123456789abcdef";
|
||||
|
||||
static zend_always_inline bool php_json_check_stack_limit(void)
|
||||
{
|
||||
#ifdef ZEND_CHECK_STACK_LIMIT
|
||||
return zend_call_stack_overflowed(EG(stack_limit));
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int php_json_determine_array_type(zval *val) /* {{{ */
|
||||
{
|
||||
zend_array *myht = Z_ARRVAL_P(val);
|
||||
@@ -115,6 +124,14 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options,
|
||||
int i, r, need_comma = 0;
|
||||
HashTable *myht, *prop_ht;
|
||||
|
||||
if (php_json_check_stack_limit()) {
|
||||
encoder->error_code = PHP_JSON_ERROR_DEPTH;
|
||||
if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
|
||||
smart_str_appendl(buf, "null", 4);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (Z_TYPE_P(val) == IS_ARRAY) {
|
||||
myht = Z_ARRVAL_P(val);
|
||||
prop_ht = NULL;
|
||||
|
||||
35
ext/json/tests/gh15168.phpt
Normal file
35
ext/json/tests/gh15168.phpt
Normal file
@@ -0,0 +1,35 @@
|
||||
--TEST--
|
||||
GH-15168 (stack overflow in json_encode())
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (ini_get('zend.max_allowed_stack_size') === false) {
|
||||
die('skip No stack limit support');
|
||||
}
|
||||
?>
|
||||
--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;
|
||||
}
|
||||
|
||||
var_dump(json_encode($firstNode, depth: 500000));
|
||||
var_dump(json_last_error());
|
||||
var_dump(json_last_error_msg());
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(false)
|
||||
int(1)
|
||||
string(28) "Maximum stack depth exceeded"
|
||||
Reference in New Issue
Block a user