Skip to content

Commit be3d128

Browse files
committed
Merge branch 'PHP-8.3' into PHP-8.4
* PHP-8.3: Fix GH-17847: xinclude destroys live node
2 parents 1eb6751 + 9beccce commit be3d128

File tree

3 files changed

+49
-57
lines changed

3 files changed

+49
-57
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ PHP NEWS
2323
Dom\HTML_NO_DEFAULT_NS). (nielsdos)
2424
. Fixed bug GH-17802 (\Dom\HTMLDocument querySelector attribute name is case
2525
sensitive in HTML). (nielsdos)
26+
. Fixed bug GH-17847 (xinclude destroys live node). (nielsdos)
2627

2728
- GD:
2829
. Fixed bug GH-17703 (imagescale with both width and height negative values

ext/dom/document.c

Lines changed: 7 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,47 +1669,6 @@ PHP_METHOD(Dom_XMLDocument, saveXml)
16691669
}
16701670
/* }}} end dom_document_savexml */
16711671

1672-
static xmlNodePtr php_dom_free_xinclude_node(xmlNodePtr cur) /* {{{ */
1673-
{
1674-
xmlNodePtr xincnode;
1675-
1676-
xincnode = cur;
1677-
cur = cur->next;
1678-
xmlUnlinkNode(xincnode);
1679-
php_libxml_node_free_resource(xincnode);
1680-
1681-
return cur;
1682-
}
1683-
/* }}} */
1684-
1685-
static void php_dom_remove_xinclude_nodes(xmlNodePtr cur) /* {{{ */
1686-
{
1687-
while(cur) {
1688-
if (cur->type == XML_XINCLUDE_START) {
1689-
cur = php_dom_free_xinclude_node(cur);
1690-
1691-
/* XML_XINCLUDE_END node will be a sibling of XML_XINCLUDE_START */
1692-
while(cur && cur->type != XML_XINCLUDE_END) {
1693-
/* remove xinclude processing nodes from recursive xincludes */
1694-
if (cur->type == XML_ELEMENT_NODE) {
1695-
php_dom_remove_xinclude_nodes(cur->children);
1696-
}
1697-
cur = cur->next;
1698-
}
1699-
1700-
if (cur && cur->type == XML_XINCLUDE_END) {
1701-
cur = php_dom_free_xinclude_node(cur);
1702-
}
1703-
} else {
1704-
if (cur->type == XML_ELEMENT_NODE) {
1705-
php_dom_remove_xinclude_nodes(cur->children);
1706-
}
1707-
cur = cur->next;
1708-
}
1709-
}
1710-
}
1711-
/* }}} */
1712-
17131672
static void dom_xinclude_strip_references(xmlNodePtr basep)
17141673
{
17151674
php_libxml_node_free_resource(basep);
@@ -1722,17 +1681,19 @@ static void dom_xinclude_strip_references(xmlNodePtr basep)
17221681
}
17231682
}
17241683

1725-
/* See GH-14702.
1726-
* We have to remove userland references to xinclude fallback nodes because libxml2 will make clones of these
1684+
/* See GH-14702 and GH-17847.
1685+
* We have to remove userland references to xinclude nodes because libxml2 will make clones of these
17271686
* and remove the original nodes. If the originals are removed while there are still userland references
17281687
* this will cause memory corruption. */
17291688
static void dom_xinclude_strip_fallback_references(const xmlNode *basep)
17301689
{
17311690
xmlNodePtr current = basep->children;
17321691

1692+
/* TODO: try to improve loop search performance */
17331693
while (current) {
1734-
if (current->type == XML_ELEMENT_NODE && current->ns != NULL && current->_private != NULL
1735-
&& xmlStrEqual(current->name, XINCLUDE_FALLBACK)
1694+
if (current->type == XML_ELEMENT_NODE
1695+
&& current->ns != NULL
1696+
&& xmlStrEqual(current->name, XINCLUDE_NODE)
17361697
&& (xmlStrEqual(current->ns->href, XINCLUDE_NS) || xmlStrEqual(current->ns->href, XINCLUDE_OLD_NS))) {
17371698
dom_xinclude_strip_references(current);
17381699
}
@@ -1745,22 +1706,11 @@ static int dom_perform_xinclude(xmlDocPtr docp, dom_object *intern, zend_long fl
17451706
{
17461707
dom_xinclude_strip_fallback_references((const xmlNode *) docp);
17471708

1709+
flags |= XML_PARSE_NOXINCNODE;
17481710
PHP_LIBXML_SANITIZE_GLOBALS(xinclude);
17491711
int err = xmlXIncludeProcessFlags(docp, (int)flags);
17501712
PHP_LIBXML_RESTORE_GLOBALS(xinclude);
17511713

1752-
/* XML_XINCLUDE_START and XML_XINCLUDE_END nodes need to be removed as these
1753-
are added via xmlXIncludeProcess to mark beginning and ending of xincluded document
1754-
but are not wanted in resulting document - must be done even if err as it could fail after
1755-
having processed some xincludes */
1756-
xmlNodePtr root = docp->children;
1757-
while (root && root->type != XML_ELEMENT_NODE && root->type != XML_XINCLUDE_START) {
1758-
root = root->next;
1759-
}
1760-
if (root) {
1761-
php_dom_remove_xinclude_nodes(root);
1762-
}
1763-
17641714
php_libxml_invalidate_node_list_cache(intern->document);
17651715

17661716
return err;

ext/dom/tests/gh17847.phpt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
GH-17847 (xinclude destroys live node)
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
$doc = new DOMDocument();
8+
$doc->loadXML(<<<XML
9+
<root>
10+
<xi:include href="thisisnonexistent" xmlns:xi="http://www.w3.org/2001/XInclude">
11+
<xi:fallback>fallback<p>garbage</p></xi:fallback>
12+
<p>garbage</p>
13+
</xi:include>
14+
<xi:test xmlns:xi="http://www.w3.org/2001/XInclude">
15+
<xi:include href="thisisnonexistent">
16+
<p>garbage</p>
17+
</xi:include>
18+
</xi:test>
19+
</root>
20+
XML);
21+
22+
$xpath = new DOMXPath($doc);
23+
24+
$garbage = [];
25+
foreach ($xpath->query('//p') as $entry)
26+
$garbage[] = $entry;
27+
28+
@$doc->xinclude();
29+
30+
foreach ($garbage as $node) {
31+
try {
32+
var_dump($node->localName);
33+
} catch (DOMException $e) {
34+
echo $e->getMessage(), "\n";
35+
}
36+
}
37+
?>
38+
--EXPECT--
39+
Invalid State Error
40+
Invalid State Error
41+
Invalid State Error

0 commit comments

Comments
 (0)