Skip to content

Commit 12ef6cc

Browse files
committed
Merge branch 'PHP-8.2' into PHP-8.3
* PHP-8.2: Fix crash in ParentNode::append() when dealing with a fragment containing text nodes
2 parents 59f1622 + 1e2a2d7 commit 12ef6cc

File tree

3 files changed

+41
-4
lines changed

3 files changed

+41
-4
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ PHP NEWS
2020
. Fix references not handled correctly in C14N. (nielsdos)
2121
. Fix crash when calling childNodes next() when iterator is exhausted.
2222
(nielsdos)
23+
. Fix crash in ParentNode::append() when dealing with a fragment
24+
containing text nodes. (nielsdos)
2325

2426
- Hash:
2527
. ext/hash: Swap the checking order of `__has_builtin` and `__GNUC__`

ext/dom/parentnode.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,22 @@ static xmlDocPtr dom_doc_from_context_node(xmlNodePtr contextNode)
146146
}
147147
}
148148

149+
/* Citing from the docs (https://gnome.pages.gitlab.gnome.org/libxml2/devhelp/libxml2-tree.html#xmlAddChild):
150+
* "Add a new node to @parent, at the end of the child (or property) list merging adjacent TEXT nodes (in which case @cur is freed)".
151+
* So we must use a custom way of adding that does not merge. */
152+
static void dom_add_child_without_merging(xmlNodePtr parent, xmlNodePtr child)
153+
{
154+
if (parent->children == NULL) {
155+
parent->children = child;
156+
} else {
157+
xmlNodePtr last = parent->last;
158+
last->next = child;
159+
child->prev = last;
160+
}
161+
parent->last = child;
162+
child->parent = parent;
163+
}
164+
149165
xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNode, zval *nodes, int nodesc)
150166
{
151167
xmlDoc *documentNode;
@@ -178,7 +194,7 @@ xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNod
178194
* So we must take a copy if this situation arises to prevent a use-after-free. */
179195
bool will_free = newNode->type == XML_TEXT_NODE && fragment->last && fragment->last->type == XML_TEXT_NODE;
180196
if (will_free) {
181-
newNode = xmlCopyNode(newNode, 1);
197+
newNode = xmlCopyNode(newNode, 0);
182198
}
183199

184200
if (newNode->type == XML_DOCUMENT_FRAG_NODE) {
@@ -187,9 +203,7 @@ xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNod
187203
while (newNode) {
188204
xmlNodePtr next = newNode->next;
189205
xmlUnlinkNode(newNode);
190-
if (!xmlAddChild(fragment, newNode)) {
191-
goto err;
192-
}
206+
dom_add_child_without_merging(fragment, newNode);
193207
newNode = next;
194208
}
195209
} else if (!xmlAddChild(fragment, newNode)) {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
Text coalesce bug when appending fragment with text nodes
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
$document = new DOMDocument();
8+
$document->loadXML('<root/>');
9+
10+
$sut = $document->createDocumentFragment();
11+
for($i = 0; $i < 10; $i++) {
12+
$textNode = $document->createTextNode("Node$i");
13+
$sut->append($textNode);
14+
}
15+
16+
$document->documentElement->append($sut);
17+
echo $document->saveXML();
18+
?>
19+
--EXPECT--
20+
<?xml version="1.0"?>
21+
<root>Node0Node1Node2Node3Node4Node5Node6Node7Node8Node9</root>

0 commit comments

Comments
 (0)