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 + +</head> + +<?xml version="1.0"?> +<head><title/>foo</head> 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-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php +$a = '<var>One</var> <var>Two</var>'; // 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 = '<var>One</var><var>Two</var>'; // 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 = '<var>One</var><var>Two</var>'; +($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) "<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> +<html><body><p>One</p> <p>Two</p></body></html> +" +string(154) "<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> +<html><body><p>One</p><p>Two</p></body></html> +" +string(154) "<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> +<html><body><p>One</p><p>Two</p></body></html> +"