From 01b74da2558009ef3c1fc0efc920172f8a82ccfc Mon Sep 17 00:00:00 2001
From: NathanFreeman <1056159381@qq.com>
Date: Wed, 8 Jun 2022 19:53:11 +0800
Subject: [PATCH 1/6] fix bug 80802
---
ext/dom/parentnode.c | 4 ++++
ext/dom/tests/bug80602.phpt | 46 +++++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+)
create mode 100644 ext/dom/tests/bug80602.phpt
diff --git a/ext/dom/parentnode.c b/ext/dom/parentnode.c
index 375c692dcad85..f0ef423764258 100644
--- a/ext/dom/parentnode.c
+++ b/ext/dom/parentnode.c
@@ -181,6 +181,10 @@ xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNod
return NULL;
}
+ if (nodesc > 1) {
+ newNode = xmlCopyNode(newNode, 1);
+ }
+
if (!xmlAddChild(fragment, newNode)) {
xmlFree(fragment);
diff --git a/ext/dom/tests/bug80602.phpt b/ext/dom/tests/bug80602.phpt
new file mode 100644
index 0000000000000..5a828067387f2
--- /dev/null
+++ b/ext/dom/tests/bug80602.phpt
@@ -0,0 +1,46 @@
+--TEST--
+Bug #80602 (Segfault when using DOMChildNode::before())
+--SKIPIF--
+
+--FILE--
+loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->before('bar', 'baz', 'cat');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->before($doc->documentElement->firstChild, 'baz', 'cat');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->before('bar', $doc->documentElement->firstChild, 'baz');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+// if `$doc->documentElement->firstChild` is the last parameter, it will cause segment fault.
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->before('bar', $doc->documentElement->firstChild, 'baz', $doc->documentElement->firstChild);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->before($doc->documentElement->firstChild, $doc->documentElement->firstChild, $doc->documentElement->firstChild);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+?>
+--EXPECTF--
+foobarbazcat
+foobazcat
+barfoobaz
+barfoobazfoo
+foofoofoo
From d3fd0f21bc5f34261767f8b96c85f1d34e569dcd Mon Sep 17 00:00:00 2001
From: NathanFreeman <1056159381@qq.com>
Date: Wed, 29 Jun 2022 19:44:57 +0800
Subject: [PATCH 2/6] fix bug 80602
---
ext/dom/parentnode.c | 55 +++++++++--
ext/dom/tests/bug80602.phpt | 155 +++++++++++++++++++++++++++--
ext/dom/tests/bug80602_2.phpt | 180 ++++++++++++++++++++++++++++++++++
3 files changed, 370 insertions(+), 20 deletions(-)
create mode 100644 ext/dom/tests/bug80602_2.phpt
diff --git a/ext/dom/parentnode.c b/ext/dom/parentnode.c
index f0ef423764258..874993c1b8a8d 100644
--- a/ext/dom/parentnode.c
+++ b/ext/dom/parentnode.c
@@ -21,6 +21,7 @@
#endif
#include "php.h"
+
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
#include "php_dom.h"
@@ -306,7 +307,9 @@ void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc)
{
xmlNode *prevsib = dom_object_get_node(context);
xmlNodePtr newchild, parentNode;
- xmlNode *fragment;
+ xmlNode *fragment, *nextsib;
+ xmlDoc *doc;
+ bool afterlastchild;
int stricterror = dom_get_strict_error(context->document);
@@ -315,7 +318,10 @@ void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc)
return;
}
+ doc = prevsib->doc;
parentNode = prevsib->parent;
+ nextsib = prevsib->next;
+ afterlastchild = (nextsib == NULL);
fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
if (fragment == NULL) {
@@ -325,13 +331,28 @@ void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc)
newchild = fragment->children;
if (newchild) {
- fragment->last->next = prevsib->next;
- prevsib->next = newchild;
+ if (!parentNode->children) {
+ prevsib = nextsib = NULL;
+ } else if (afterlastchild) {
+ prevsib = parentNode->children == prevsib ? prevsib : parentNode->last;
+ } else {
+ prevsib = parentNode->children == prevsib ? prevsib : NULL;
+ }
- newchild->prev = prevsib;
+ if (prevsib) {
+ fragment->last->next = prevsib->next;
+ prevsib->next = newchild;
+ } else {
+ parentNode->children = newchild;
+ if (nextsib) {
+ newchild->next = nextsib;
+ nextsib->prev = newchild;
+ }
+ }
+ newchild->prev = prevsib;
dom_fragment_assign_parent_node(parentNode, fragment);
- dom_reconcile_ns(prevsib->doc, newchild);
+ dom_reconcile_ns(doc, newchild);
}
xmlFree(fragment);
@@ -341,10 +362,15 @@ void dom_parent_node_before(dom_object *context, zval *nodes, int nodesc)
{
xmlNode *nextsib = dom_object_get_node(context);
xmlNodePtr newchild, prevsib, parentNode;
- xmlNode *fragment;
+ xmlNode *fragment, *afternextsib;
+ xmlDoc *doc;
+ bool beforefirstchild;
+ doc = nextsib->doc;
prevsib = nextsib->prev;
+ afternextsib = nextsib->next;
parentNode = nextsib->parent;
+ beforefirstchild = !prevsib;
fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
if (fragment == NULL) {
@@ -354,19 +380,28 @@ void dom_parent_node_before(dom_object *context, zval *nodes, int nodesc)
newchild = fragment->children;
if (newchild) {
+ if (!parentNode->children) {
+ nextsib = NULL;
+ } else if (beforefirstchild) {
+ nextsib = parentNode->children == nextsib ? nextsib : afternextsib;
+ } else {
+ nextsib = parentNode->children == prevsib ? prevsib->next : nextsib;
+ }
+
if (parentNode->children == nextsib) {
parentNode->children = newchild;
} else {
prevsib->next = newchild;
}
+
fragment->last->next = nextsib;
- nextsib->prev = fragment->last;
+ if (nextsib) {
+ nextsib->prev = fragment->last;
+ }
newchild->prev = prevsib;
-
dom_fragment_assign_parent_node(parentNode, fragment);
-
- dom_reconcile_ns(nextsib->doc, newchild);
+ dom_reconcile_ns(doc, newchild);
}
xmlFree(fragment);
diff --git a/ext/dom/tests/bug80602.phpt b/ext/dom/tests/bug80602.phpt
index 5a828067387f2..064e856b60e64 100644
--- a/ext/dom/tests/bug80602.phpt
+++ b/ext/dom/tests/bug80602.phpt
@@ -6,41 +6,176 @@ Bug #80602 (Segfault when using DOMChildNode::before())
loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->before($target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
$doc = new \DOMDocument();
$doc->loadXML('foo');
$target = $doc->documentElement->lastChild;
-$target->before('bar', 'baz', 'cat');
+$target->before($target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->before($doc->documentElement->lastChild);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->before($doc->documentElement->firstChild);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->before($target, $doc->documentElement->lastChild);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->before($doc->documentElement->lastChild, $target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
$doc = new \DOMDocument();
$doc->loadXML('foo');
$target = $doc->documentElement->lastChild;
-$target->before($doc->documentElement->firstChild, 'baz', 'cat');
+$target->before($target, $doc->documentElement->firstChild);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('foo');
$target = $doc->documentElement->lastChild;
-$target->before('bar', $doc->documentElement->firstChild, 'baz');
+$target->before($doc->documentElement->firstChild, $target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->before('bar','baz');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
-// if `$doc->documentElement->firstChild` is the last parameter, it will cause segment fault.
$doc = new \DOMDocument();
$doc->loadXML('foo');
$target = $doc->documentElement->lastChild;
-$target->before('bar', $doc->documentElement->firstChild, 'baz', $doc->documentElement->firstChild);
+$target->before('bar','baz');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->before($target, 'bar','baz');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->before('bar', $target, 'baz');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->before('bar', 'baz', $target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+
$doc = new \DOMDocument();
$doc->loadXML('foo');
$target = $doc->documentElement->lastChild;
-$target->before($doc->documentElement->firstChild, $doc->documentElement->firstChild, $doc->documentElement->firstChild);
+$target->before($target, 'bar','baz');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->before('bar', $target, 'baz');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->before('bar', 'baz', $target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->before('bar', $target, $doc->documentElement->lastChild);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->before($target, 'bar', $doc->documentElement->lastChild);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->before($target, $doc->documentElement->lastChild, 'bar');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->before('bar', $doc->documentElement->firstChild, $target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->before($doc->documentElement->firstChild, 'bar', $target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->before($doc->documentElement->firstChild, $target, 'bar');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
?>
--EXPECTF--
-foobarbazcat
-foobazcat
+foo
+foo
+foo
+foo
+foo
+foo
+foo
+foo
+barbazfoo
+foobarbaz
+foobarbaz
barfoobaz
-barfoobazfoo
-foofoofoo
+barbazfoo
+foobarbaz
+foobarbaz
+foobarbaz
+barfoo
+foobar
+foobar
+barfoo
+foobar
+foobar
+
diff --git a/ext/dom/tests/bug80602_2.phpt b/ext/dom/tests/bug80602_2.phpt
new file mode 100644
index 0000000000000..9d697c64172a0
--- /dev/null
+++ b/ext/dom/tests/bug80602_2.phpt
@@ -0,0 +1,180 @@
+--TEST--
+Bug #80602 (Segfault when using DOMChildNode::after())
+--SKIPIF--
+
+--FILE--
+loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->after($target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->after($target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->after($doc->documentElement->lastChild);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->after($doc->documentElement->firstChild);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->after($target, $doc->documentElement->lastChild);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->after($doc->documentElement->lastChild, $target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->after($target, $doc->documentElement->firstChild);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->after($doc->documentElement->firstChild, $target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->after('bar','baz');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->after('bar','baz');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->after($target, 'bar','baz');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->after('bar', $target, 'baz');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->after('bar', 'baz', $target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->after($target, 'bar','baz');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->after('bar', $target, 'baz');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->after('bar', 'baz', $target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->after('bar', $target, $doc->documentElement->lastChild);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->after($target, 'bar', $doc->documentElement->lastChild);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->firstChild;
+$target->after($target, $doc->documentElement->lastChild, 'bar');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->after('bar', $doc->documentElement->firstChild, $target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->after($doc->documentElement->firstChild, 'bar', $target);
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+
+$doc = new \DOMDocument();
+$doc->loadXML('foo');
+$target = $doc->documentElement->lastChild;
+$target->after($doc->documentElement->firstChild, $target, 'bar');
+echo $doc->saveXML($doc->documentElement).PHP_EOL;
+
+?>
+--EXPECTF--
+foo
+foo
+foo
+foo
+foo
+foo
+foo
+foo
+foobarbaz
+foobarbaz
+foobarbaz
+barfoobaz
+barbazfoo
+foobarbaz
+foobarbaz
+foobarbaz
+barfoo
+foobar
+foobar
+barfoo
+foobar
+foobar
From fb2293cbc7e42e209021300d1b27ebe8e66bc232 Mon Sep 17 00:00:00 2001
From: NathanFreeman <1056159381@qq.com>
Date: Wed, 20 Jul 2022 21:26:00 +0800
Subject: [PATCH 3/6] fix bug 81642
---
ext/dom/element.c | 39 ++++++++++++++++++++-----------------
ext/dom/parentnode.c | 23 ++++++++++++++++++++++
ext/dom/tests/bug81642.phpt | 18 +++++++++++++++++
3 files changed, 62 insertions(+), 18 deletions(-)
create mode 100644 ext/dom/tests/bug81642.phpt
diff --git a/ext/dom/element.c b/ext/dom/element.c
index 4835c7fad91ad..3f2fe7294f09e 100644
--- a/ext/dom/element.c
+++ b/ext/dom/element.c
@@ -20,6 +20,7 @@
#endif
#include "php.h"
+
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
#include "php_dom.h"
@@ -74,14 +75,14 @@ PHP_METHOD(DOMElement, __construct)
RETURN_THROWS();
}
} else {
- /* If you don't pass a namespace uri, then you can't set a prefix */
- localname = (char *) xmlSplitQName2((xmlChar *) name, (xmlChar **) &prefix);
- if (prefix != NULL) {
+ /* If you don't pass a namespace uri, then you can't set a prefix */
+ localname = (char *) xmlSplitQName2((xmlChar *) name, (xmlChar **) &prefix);
+ if (prefix != NULL) {
xmlFree(localname);
xmlFree(prefix);
- php_dom_throw_error(NAMESPACE_ERR, 1);
- RETURN_THROWS();
- }
+ php_dom_throw_error(NAMESPACE_ERR, 1);
+ RETURN_THROWS();
+ }
nodep = xmlNewNode(NULL, (xmlChar *) name);
}
@@ -152,8 +153,8 @@ int dom_element_schema_type_info_read(dom_object *obj, zval *retval)
static xmlNodePtr dom_get_dom1_attribute(xmlNodePtr elem, xmlChar *name) /* {{{ */
{
- int len;
- const xmlChar *nqname;
+ int len;
+ const xmlChar *nqname;
nqname = xmlSplitQName3(name, &len);
if (nqname != NULL) {
@@ -570,9 +571,9 @@ PHP_METHOD(DOMElement, getAttributeNS)
static xmlNsPtr _dom_new_reconNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) /* {{{ */
{
- xmlNsPtr def;
- xmlChar prefix[50];
- int counter = 1;
+ xmlNsPtr def;
+ xmlChar prefix[50];
+ int counter = 1;
if ((tree == NULL) || (ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
return NULL;
@@ -883,12 +884,12 @@ PHP_METHOD(DOMElement, setAttributeNodeNS)
RETURN_FALSE;
}
- nsp = attrp->ns;
- if (nsp != NULL) {
- existattrp = xmlHasNsProp(nodep, nsp->href, attrp->name);
- } else {
- existattrp = xmlHasProp(nodep, attrp->name);
- }
+ nsp = attrp->ns;
+ if (nsp != NULL) {
+ existattrp = xmlHasNsProp(nodep, nsp->href, attrp->name);
+ } else {
+ existattrp = xmlHasProp(nodep, attrp->name);
+ }
if (existattrp != NULL && existattrp->type != XML_ATTRIBUTE_DECL) {
if ((oldobj = php_dom_object_get_data((xmlNodePtr) existattrp)) != NULL &&
@@ -1252,7 +1253,9 @@ PHP_METHOD(DOMElement, replaceWith)
DOM_GET_OBJ(context, id, xmlNodePtr, intern);
dom_parent_node_after(intern, args, argc);
- dom_child_node_remove(intern);
+ if (!dom_node_is_argument (intern, args, argc)) {
+ dom_child_node_remove(intern);
+ }
}
/* }}} end DOMElement::prepend */
diff --git a/ext/dom/parentnode.c b/ext/dom/parentnode.c
index 874993c1b8a8d..278256044950a 100644
--- a/ext/dom/parentnode.c
+++ b/ext/dom/parentnode.c
@@ -407,6 +407,29 @@ void dom_parent_node_before(dom_object *context, zval *nodes, int nodesc)
xmlFree(fragment);
}
+bool dom_node_is_argument(dom_object *context, zval *nodes, int nodesc)
+{
+ int i;
+ xmlNode *newNode;
+ zend_class_entry *ce;
+ dom_object *newNodeObj;
+ xmlNode *child = dom_object_get_node(context);
+
+ for (i = 0; i < nodesc; i++) {
+ if (Z_TYPE(nodes[i]) == IS_OBJECT) {
+ ce = Z_OBJCE(nodes[i]);
+ if (instanceof_function(ce, dom_node_class_entry)) {
+ newNodeObj = Z_DOMOBJ_P(&nodes[i]);
+ newNode = dom_object_get_node(newNodeObj);
+ if (child == newNode) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
void dom_child_node_remove(dom_object *context)
{
xmlNode *child = dom_object_get_node(context);
diff --git a/ext/dom/tests/bug81642.phpt b/ext/dom/tests/bug81642.phpt
new file mode 100644
index 0000000000000..83656f80c9a50
--- /dev/null
+++ b/ext/dom/tests/bug81642.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Bug #81642 DOMChildNode::replaceWith() bug when replacing a node with itself.
+--SKIPIF--
+
+--FILE--
+loadXML('firstsecond');
+$element = $dom->documentElement->firstChild;
+$element->replaceWith($element);
+
+print_node_list_compact($dom->documentElement->childNodes);
+?>
+--EXPECT--
+firstsecond
+
From e81f4dcb833155729b2f50dc621947b1b310bafe Mon Sep 17 00:00:00 2001
From: NathanFreeman <1056159381@qq.com>
Date: Wed, 20 Jul 2022 23:32:32 +0800
Subject: [PATCH 4/6] fix bug #81642
---
ext/dom/tests/bug81642.phpt | 26 ++++++++++++++++++++------
1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/ext/dom/tests/bug81642.phpt b/ext/dom/tests/bug81642.phpt
index 83656f80c9a50..b1581cfdb14ba 100644
--- a/ext/dom/tests/bug81642.phpt
+++ b/ext/dom/tests/bug81642.phpt
@@ -6,13 +6,27 @@ Bug #81642 DOMChildNode::replaceWith() bug when replacing a node with itself.
loadXML('firstsecond');
-$element = $dom->documentElement->firstChild;
-$element->replaceWith($element);
+$doc = new DOMDocument;
+$headNode = $doc->createElement("head");
+$doc->appendChild($headNode);
+$titleNode = $doc->createElement("title");
+$headNode->appendChild($titleNode);
+$titleNode->replaceWith($titleNode);
+echo $doc->saveXML().PHP_EOL;
+
+$doc = new DOMDocument;
+$headNode = $doc->createElement("head");
+$doc->appendChild($headNode);
+$titleNode = $doc->createElement("title");
+$headNode->appendChild($titleNode);
+$titleNode->replaceWith($titleNode, 'foo');
+echo $doc->saveXML().PHP_EOL;
-print_node_list_compact($dom->documentElement->childNodes);
?>
--EXPECT--
-firstsecond
+
+
+
+
+foo
From 845c80cf297a3eecb0517929c479199a271fba29 Mon Sep 17 00:00:00 2001
From: NathanFreeman <1056159381@qq.com>
Date: Wed, 20 Jul 2022 23:52:39 +0800
Subject: [PATCH 5/6] fix build error in macos
---
ext/dom/element.c | 2 +-
ext/dom/php_dom.h | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/ext/dom/element.c b/ext/dom/element.c
index 3f2fe7294f09e..b36c5b78dc8db 100644
--- a/ext/dom/element.c
+++ b/ext/dom/element.c
@@ -1253,7 +1253,7 @@ PHP_METHOD(DOMElement, replaceWith)
DOM_GET_OBJ(context, id, xmlNodePtr, intern);
dom_parent_node_after(intern, args, argc);
- if (!dom_node_is_argument (intern, args, argc)) {
+ if (!dom_node_is_argument(intern, args, argc)) {
dom_child_node_remove(intern);
}
}
diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h
index 24e1ea646a05d..a39ce6914e3b4 100644
--- a/ext/dom/php_dom.h
+++ b/ext/dom/php_dom.h
@@ -130,6 +130,7 @@ void dom_parent_node_prepend(dom_object *context, zval *nodes, int nodesc);
void dom_parent_node_append(dom_object *context, zval *nodes, int nodesc);
void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc);
void dom_parent_node_before(dom_object *context, zval *nodes, int nodesc);
+bool dom_node_is_argument(dom_object *context, zval *nodes, int nodesc);
void dom_child_node_remove(dom_object *context);
#define REGISTER_DOM_CLASS(ce, name, parent_ce, funcs, entry) \
From 19d775122c23fe8632241fab037c956cb8160d47 Mon Sep 17 00:00:00 2001
From: NathanFreeman <1056159381@qq.com>
Date: Wed, 27 Jul 2022 19:34:24 +0800
Subject: [PATCH 6/6] fix bug #9142
---
ext/dom/parentnode.c | 7 +++++--
ext/dom/tests/gh9142.phpt | 40 +++++++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+), 2 deletions(-)
create mode 100644 ext/dom/tests/gh9142.phpt
diff --git a/ext/dom/parentnode.c b/ext/dom/parentnode.c
index 278256044950a..5c22d6636be48 100644
--- a/ext/dom/parentnode.c
+++ b/ext/dom/parentnode.c
@@ -341,12 +341,15 @@ void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc)
if (prevsib) {
fragment->last->next = prevsib->next;
+ if (prevsib->next) {
+ prevsib->next->prev = fragment->last;
+ }
prevsib->next = newchild;
} else {
parentNode->children = newchild;
if (nextsib) {
- newchild->next = nextsib;
- nextsib->prev = newchild;
+ fragment->last->next = nextsib;
+ nextsib->prev = fragment->last;
}
}
diff --git a/ext/dom/tests/gh9142.phpt b/ext/dom/tests/gh9142.phpt
new file mode 100644
index 0000000000000..bae8cc2f3ff68
--- /dev/null
+++ b/ext/dom/tests/gh9142.phpt
@@ -0,0 +1,40 @@
+--TEST--
+GitHub #9142 (DOMChildNode replaceWith() double-free error when replacing elements not separated by any whitespace)
+--SKIPIF--
+
+--FILE--
+One Two'; // Works fine
+($domA = new DOMDocument('1.0', 'UTF-8'))->loadHTML($a);
+foreach ((new DOMXPath($domA))->query('//var') as $var) {
+ $var->replaceWith($domA->createElement('p', $var->nodeValue));
+}
+var_dump($domA->saveHTML());
+
+
+$b = 'OneTwo'; // Causes a 'double free' error
+($domB = new DOMDocument('1.0', 'UTF-8'))->loadHTML($b);
+foreach ((new DOMXPath($domB))->query('//var') as $var) {
+ $var->replaceWith($domB->createElement('p', $var->nodeValue));
+}
+var_dump($domB->saveHTML());
+
+
+$document = 'OneTwo';
+($dom = new DOMDocument('1.0', 'UTF-8'))->loadHTML($document);
+foreach ((new DOMXPath($dom))->query('//var') as $var) {
+ $var->after($dom->createElement('p', $var->nodeValue));
+ $var->remove();
+}
+var_dump($dom->saveHTML());
+?>
+--EXPECT--
+string(155) "
+One
Two
+"
+string(154) "
+One
Two
+"
+string(154) "
+One
Two
+"