Skip to content

Commit bcdba83

Browse files
committed
Merge branch 'PHP-8.3'
* PHP-8.3: Fix GH-14702: DOMDocument::xinclude() crash
2 parents 2fc27b7 + 0a1f51d commit bcdba83

File tree

2 files changed

+88
-1
lines changed

2 files changed

+88
-1
lines changed

ext/dom/document.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1706,9 +1706,41 @@ static void php_dom_remove_xinclude_nodes(xmlNodePtr cur) /* {{{ */
17061706
}
17071707
/* }}} */
17081708

1709-
/* {{{ Substitutes xincludes in a DomDocument */
1709+
static void dom_xinclude_strip_references(xmlNodePtr basep)
1710+
{
1711+
php_libxml_node_free_resource(basep);
1712+
1713+
xmlNodePtr current = basep->children;
1714+
1715+
while (current) {
1716+
php_libxml_node_free_resource(current);
1717+
current = php_dom_next_in_tree_order(current, basep);
1718+
}
1719+
}
1720+
1721+
/* See GH-14702.
1722+
* We have to remove userland references to xinclude fallback nodes because libxml2 will make clones of these
1723+
* and remove the original nodes. If the originals are removed while there are still userland references
1724+
* this will cause memory corruption. */
1725+
static void dom_xinclude_strip_fallback_references(const xmlNode *basep)
1726+
{
1727+
xmlNodePtr current = basep->children;
1728+
1729+
while (current) {
1730+
if (current->type == XML_ELEMENT_NODE && current->ns != NULL && current->_private != NULL
1731+
&& xmlStrEqual(current->name, XINCLUDE_FALLBACK)
1732+
&& (xmlStrEqual(current->ns->href, XINCLUDE_NS) || xmlStrEqual(current->ns->href, XINCLUDE_OLD_NS))) {
1733+
dom_xinclude_strip_references(current);
1734+
}
1735+
1736+
current = php_dom_next_in_tree_order(current, basep);
1737+
}
1738+
}
1739+
17101740
static int dom_perform_xinclude(xmlDocPtr docp, dom_object *intern, zend_long flags)
17111741
{
1742+
dom_xinclude_strip_fallback_references((const xmlNode *) docp);
1743+
17121744
PHP_LIBXML_SANITIZE_GLOBALS(xinclude);
17131745
int err = xmlXIncludeProcessFlags(docp, (int)flags);
17141746
PHP_LIBXML_RESTORE_GLOBALS(xinclude);
@@ -1730,6 +1762,7 @@ static int dom_perform_xinclude(xmlDocPtr docp, dom_object *intern, zend_long fl
17301762
return err;
17311763
}
17321764

1765+
/* {{{ Substitutues xincludes in a DomDocument */
17331766
PHP_METHOD(DOMDocument, xinclude)
17341767
{
17351768
xmlDoc *docp;

ext/dom/tests/gh14702.phpt

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
--TEST--
2+
GH-14702 (DOMDocument::xinclude() crash)
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
$doc = new DOMDocument();
8+
$doc->loadXML(<<<XML
9+
<?xml version="1.0"?>
10+
<root>
11+
<child/>
12+
<include href="foo" xmlns="http://www.w3.org/2001/XInclude">
13+
<fallback/>
14+
</include>
15+
<keep/>
16+
</root>
17+
XML);
18+
$xi = $doc->createElementNS('http://www.w3.org/2001/XInclude', 'xi:include');
19+
$xi->setAttribute('href', 'nonexistent');
20+
21+
$fallback = $doc->createElementNS('http://www.w3.org/2001/XInclude', 'xi:fallback');
22+
$xi->appendChild($fallback);
23+
$child1 = $fallback->appendChild($doc->createElement('fallback-child1'));
24+
$child2 = $fallback->appendChild($doc->createElement('fallback-child2'));
25+
26+
$xpath = new DOMXPath($doc);
27+
$toReplace = $xpath->query('//child')->item(0);
28+
$toReplace->parentNode->replaceChild($xi, $toReplace);
29+
30+
$keep = $doc->documentElement->lastElementChild;
31+
32+
var_dump(@$doc->xinclude());
33+
echo $doc->saveXML();
34+
35+
var_dump($keep->nodeName);
36+
37+
$keep->textContent = 'still works';
38+
echo $doc->saveXML();
39+
?>
40+
--EXPECT--
41+
int(2)
42+
<?xml version="1.0"?>
43+
<root>
44+
<fallback-child1/><fallback-child2/>
45+
46+
<keep/>
47+
</root>
48+
string(4) "keep"
49+
<?xml version="1.0"?>
50+
<root>
51+
<fallback-child1/><fallback-child2/>
52+
53+
<keep>still works</keep>
54+
</root>

0 commit comments

Comments
 (0)