[php-src] master: Merge branch 'PHP-8.4' into PHP-8.5

From: Date: Sat, 08 Aug 2026 16:19:08 +0000
Subject: [php-src] master: Merge branch 'PHP-8.4' into PHP-8.5
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-140544@lists.php.net to get a copy of this message
Author: Weilin Du (LamentXU123) Date: 2026-08-09T00:14:16+08:00 Commit: https://github.com/php/php-src/commit/19eda22e90bc6e1a7265263ee17d9ed6af685d5f Raw diff: https://github.com/php/php-src/commit/19eda22e90bc6e1a7265263ee17d9ed6af685d5f.diff Merge branch 'PHP-8.4' into PHP-8.5 * PHP-8.4: Fix GH-23120: DOMNode::isEqualNode stack overflow on deeply nested trees (#23140) Changed paths: A ext/dom/tests/gh23120.phpt M NEWS M ext/dom/node.c Diff: diff --git a/NEWS b/NEWS index 19cb73aba23e..7fcd21fbbdca 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,8 @@ PHP NEWS Dom\XMLDocument). (Lazizbek Ergashev) . Fixed bug GH-22825 (DOMElement::setAttribute() fails silently when the DTD declares a default value for the attribute). (iliaal) + . Fixed bug GH-23120 (Stack overflow when comparing deeply nested DOM nodes + with DOMNode::isEqualNode()). (Weilin Du) - Intl: . Fixed IntlListFormatter::__construct() leaving stale global error state diff --git a/ext/dom/node.c b/ext/dom/node.c index 04e03c1b0120..0eb4e2a31c46 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -1730,11 +1730,27 @@ static bool php_dom_is_equal_attr(const xmlAttr *this_attr, const xmlAttr *other && php_dom_node_is_content_equal((const xmlNode *) this_attr, (const xmlNode *) other_attr); } +static zend_always_inline bool php_dom_node_is_equal_node_check_stack_limit(void) +{ +#ifdef ZEND_CHECK_STACK_LIMIT + return zend_call_stack_overflowed(EG(stack_limit)); +#else + return false; +#endif +} + static bool php_dom_node_is_equal_node(const xmlNode *this, const xmlNode *other, bool spec_compliant) { ZEND_ASSERT(this != NULL); ZEND_ASSERT(other != NULL); + if (UNEXPECTED(php_dom_node_is_equal_node_check_stack_limit())) { + if (!EG(exception)) { + zend_throw_error(NULL, "Maximum call stack size reached."); + } + return false; + } + if (this->type != other->type) { return false; } @@ -1795,6 +1811,7 @@ static void dom_node_is_equal_node_common(INTERNAL_FUNCTION_PARAMETERS, bool mod zval *id, *node; xmlNodePtr otherp, nodep; dom_object *intern; + bool result; id = ZEND_THIS; ZEND_PARSE_PARAMETERS_START(1, 1) @@ -1817,7 +1834,11 @@ static void dom_node_is_equal_node_common(INTERNAL_FUNCTION_PARAMETERS, bool mod RETURN_BOOL(nodep == NULL && otherp == NULL); } - RETURN_BOOL(php_dom_node_is_equal_node(nodep, otherp, modern)); + result = php_dom_node_is_equal_node(nodep, otherp, modern); + if (UNEXPECTED(EG(exception))) { + RETURN_THROWS(); + } + RETURN_BOOL(result); } PHP_METHOD(DOMNode, isEqualNode) diff --git a/ext/dom/tests/gh23120.phpt b/ext/dom/tests/gh23120.phpt new file mode 100644 index 000000000000..511314d9cbba --- /dev/null +++ b/ext/dom/tests/gh23120.phpt @@ -0,0 +1,42 @@ +--TEST-- +GH-23120 (Stack overflow when comparing deeply nested DOM nodes) +--EXTENSIONS-- +dom +--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 +function create_deep_document(): DOMDocument { + $doc = new DOMDocument(); + $node = $doc->createElement('leaf', 'x'); + + for ($i = 0; $i < 10000; $i++) { + $parent = $doc->createElement('a'); + $parent->appendChild($node); + $node = $parent; + } + + $doc->appendChild($node); + return $doc; +} + +$doc1 = create_deep_document(); +$doc2 = create_deep_document(); + +try { + var_dump($doc1->documentElement->isEqualNode($doc2->documentElement)); +} catch (\Error $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Error: Maximum call stack size reached.

« previous php.cvs (#140544) next »