Skip to content

Commit 3023b29

Browse files
committed
Merge branch 'PHP-8.3' into PHP-8.4
* PHP-8.3: Fix phpGH-19612: Mitigate libxml2 tree dictionary bug
2 parents e4c9482 + 080fd14 commit 3023b29

File tree

3 files changed

+64
-15
lines changed

3 files changed

+64
-15
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ PHP NEWS
1515
. Fixed date_sunrise() and date_sunset() with partial-hour UTC offset.
1616
(ilutov)
1717

18+
- DOM:
19+
. Fixed bug GH-19612 (Mitigate libxml2 tree dictionary bug). (nielsdos)
20+
1821
- FPM:
1922
. Fixed failed debug assertion when php_admin_value setting fails. (ilutov)
2023

ext/dom/document.c

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,8 +1104,9 @@ static void php_dom_transfer_document_ref(xmlNodePtr node, php_libxml_ref_obj *n
11041104
}
11051105
}
11061106

1107-
/* Workaround for bug that was fixed in https://github.com/GNOME/libxml2/commit/4bc3ebf3eaba352fbbce2ef70ad00a3c7752478a */
1108-
#if LIBXML_VERSION < 21000
1107+
/* Workaround for bug that was fixed in https://github.com/GNOME/libxml2/commit/4bc3ebf3eaba352fbbce2ef70ad00a3c7752478a
1108+
* and https://github.com/GNOME/libxml2/commit/bc7ab5a2e61e4b36accf6803c5b0e245c11154b1 */
1109+
#if LIBXML_VERSION < 21300
11091110
static xmlChar *libxml_copy_dicted_string(xmlDictPtr src_dict, xmlDictPtr dst_dict, xmlChar *str)
11101111
{
11111112
if (str == NULL) {
@@ -1122,30 +1123,43 @@ static xmlChar *libxml_copy_dicted_string(xmlDictPtr src_dict, xmlDictPtr dst_di
11221123

11231124
static void libxml_fixup_name_and_content(xmlDocPtr src_doc, xmlDocPtr dst_doc, xmlNodePtr node)
11241125
{
1125-
if (src_doc != NULL && dst_doc != src_doc && src_doc->dict != NULL) {
1126+
if (node->type == XML_ENTITY_REF_NODE) {
1127+
node->children = NULL; /* Break link with original document. */
1128+
}
1129+
if (src_doc != NULL && src_doc->dict != NULL) {
1130+
ZEND_ASSERT(dst_doc != src_doc);
11261131
node->name = libxml_copy_dicted_string(src_doc->dict, dst_doc->dict, BAD_CAST node->name);
11271132
node->content = libxml_copy_dicted_string(src_doc->dict, NULL, node->content);
11281133
}
11291134
}
11301135

1131-
static void libxml_fixup_name_and_content_element(xmlDocPtr src_doc, xmlDocPtr dst_doc, xmlNodePtr node)
1136+
static void libxml_fixup_name_and_content_outer(xmlDocPtr src_doc, xmlDocPtr dst_doc, xmlNodePtr node)
11321137
{
11331138
libxml_fixup_name_and_content(src_doc, dst_doc, node);
1134-
for (xmlAttrPtr attr = node->properties; attr != NULL; attr = attr->next) {
1135-
libxml_fixup_name_and_content(src_doc, dst_doc, (xmlNodePtr) attr);
1139+
1140+
if (node->type == XML_ELEMENT_NODE) {
1141+
for (xmlAttrPtr attr = node->properties; attr != NULL; attr = attr->next) {
1142+
libxml_fixup_name_and_content(src_doc, dst_doc, (xmlNodePtr) attr);
1143+
for (xmlNodePtr attr_child = attr->children; attr_child != NULL; attr_child = attr_child->next) {
1144+
libxml_fixup_name_and_content(src_doc, dst_doc, attr_child);
1145+
}
1146+
}
11361147
}
11371148

1138-
for (xmlNodePtr child = node->children; child != NULL; child = child->next) {
1139-
libxml_fixup_name_and_content_element(src_doc, dst_doc, child);
1149+
if (node->type == XML_ELEMENT_NODE || node->type == XML_ATTRIBUTE_NODE) {
1150+
for (xmlNodePtr child = node->children; child != NULL; child = child->next) {
1151+
libxml_fixup_name_and_content_outer(src_doc, dst_doc, child);
1152+
}
11401153
}
11411154
}
11421155
#endif
11431156

11441157
bool php_dom_adopt_node(xmlNodePtr nodep, dom_object *dom_object_new_document, xmlDocPtr new_document)
11451158
{
1146-
xmlDocPtr original_document = nodep->doc;
1147-
php_libxml_invalidate_node_list_cache_from_doc(original_document);
1148-
if (nodep->doc != new_document) {
1159+
xmlDocPtr old_doc = nodep->doc;
1160+
1161+
php_libxml_invalidate_node_list_cache_from_doc(old_doc);
1162+
if (old_doc != new_document) {
11491163
php_libxml_invalidate_node_list_cache(dom_object_new_document->document);
11501164

11511165
/* Note for ATTRIBUTE_NODE: specified is always true in ext/dom,
@@ -1155,16 +1169,18 @@ bool php_dom_adopt_node(xmlNodePtr nodep, dom_object *dom_object_new_document, x
11551169
xmlSetTreeDoc(nodep, new_document);
11561170
php_dom_libxml_ns_mapper *ns_mapper = php_dom_get_ns_mapper(dom_object_new_document);
11571171
php_dom_libxml_reconcile_modern(ns_mapper, nodep);
1158-
#if LIBXML_VERSION < 21000
1159-
libxml_fixup_name_and_content_element(original_document, new_document, nodep);
1160-
#endif
11611172
} else {
1162-
int ret = xmlDOMWrapAdoptNode(NULL, original_document, nodep, new_document, NULL, /* options, unused */ 0);
1173+
int ret = xmlDOMWrapAdoptNode(NULL, old_doc, nodep, new_document, NULL, /* options, unused */ 0);
11631174
if (UNEXPECTED(ret != 0)) {
11641175
return false;
11651176
}
11661177
}
11671178

1179+
#if LIBXML_VERSION < 21300
1180+
/* Must be first before transferring the ref to ensure the old document dictionary stays alive. */
1181+
libxml_fixup_name_and_content_outer(old_doc, new_document, nodep);
1182+
#endif
1183+
11681184
php_dom_transfer_document_ref(nodep, dom_object_new_document->document);
11691185
} else {
11701186
xmlUnlinkNode(nodep);

ext/dom/tests/gh19612.phpt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
GH-19612 (Mitigate libxml2 tree dictionary bug)
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
$xml = new DOMDocument;
8+
$xml->loadXML(<<<XML
9+
<!DOCTYPE root [
10+
<!ENTITY foo "foo">
11+
]>
12+
<root><el x="&foo;"/></root>
13+
XML);
14+
$html = new DOMDocument;
15+
$html->loadHTML('<p>foo</p>', LIBXML_NOERROR);
16+
$p = $html->documentElement->firstChild->firstChild;
17+
$p->appendChild($html->adoptNode($xml->documentElement->firstElementChild->cloneNode(true)));
18+
19+
echo $html->saveXML();
20+
echo $xml->saveXML();
21+
?>
22+
--EXPECT--
23+
<?xml version="1.0" standalone="yes"?>
24+
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
25+
<html><body><p>foo<el x="&foo;"/></p></body></html>
26+
<?xml version="1.0"?>
27+
<!DOCTYPE root [
28+
<!ENTITY foo "foo">
29+
]>
30+
<root><el x="&foo;"/></root>

0 commit comments

Comments
 (0)