1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Merge branch 'PHP-8.2'

* PHP-8.2:
  Fix GH-11288 and GH-11289 and GH-11290 and GH-9142: DOMExceptions and segfaults with replaceWith
This commit is contained in:
nielsdos
2023-05-25 23:06:51 +02:00
9 changed files with 486 additions and 173 deletions

View File

@@ -124,6 +124,23 @@ int dom_parent_node_child_element_count(dom_object *obj, zval *retval)
}
/* }}} */
static bool dom_is_node_in_list(const zval *nodes, int nodesc, const xmlNodePtr node_to_find)
{
for (int i = 0; i < nodesc; i++) {
if (Z_TYPE(nodes[i]) == IS_OBJECT) {
const zend_class_entry *ce = Z_OBJCE(nodes[i]);
if (instanceof_function(ce, dom_node_class_entry)) {
if (dom_object_get_node(Z_DOMOBJ_P(nodes + i)) == node_to_find) {
return true;
}
}
}
}
return false;
}
xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNode, zval *nodes, int nodesc)
{
int i;
@@ -177,17 +194,16 @@ xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNod
goto hierarchy_request_err;
}
/*
* xmlNewDocText function will always returns same address to the second parameter if the parameters are greater than or equal to three.
* If it's text, that's fine, but if it's an object, it can cause invalid pointer because many new nodes point to the same memory address.
* So we must copy the new node to avoid this situation.
*/
if (nodesc > 1) {
/* Citing from the docs (https://gnome.pages.gitlab.gnome.org/libxml2/devhelp/libxml2-tree.html#xmlAddChild):
* "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)".
* So we must take a copy if this situation arises to prevent a use-after-free. */
bool will_free = newNode->type == XML_TEXT_NODE && fragment->last && fragment->last->type == XML_TEXT_NODE;
if (will_free) {
newNode = xmlCopyNode(newNode, 1);
}
if (!xmlAddChild(fragment, newNode)) {
if (nodesc > 1) {
if (will_free) {
xmlFreeNode(newNode);
}
goto hierarchy_request_err;
@@ -303,25 +319,64 @@ void dom_parent_node_prepend(dom_object *context, zval *nodes, int nodesc)
xmlFree(fragment);
}
static void dom_pre_insert(xmlNodePtr insertion_point, xmlNodePtr parentNode, xmlNodePtr newchild, xmlNodePtr fragment)
{
if (!insertion_point) {
/* Place it as last node */
if (parentNode->children) {
/* There are children */
fragment->last->prev = parentNode->last;
newchild->prev = parentNode->last->prev;
parentNode->last->next = newchild;
} else {
/* No children, because they moved out when they became a fragment */
parentNode->children = newchild;
parentNode->last = newchild;
}
} else {
/* Insert fragment before insertion_point */
fragment->last->next = insertion_point;
if (insertion_point->prev) {
insertion_point->prev->next = newchild;
newchild->prev = insertion_point->prev;
}
insertion_point->prev = newchild;
if (parentNode->children == insertion_point) {
parentNode->children = newchild;
}
}
}
void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc)
{
/* Spec link: https://dom.spec.whatwg.org/#dom-childnode-after */
xmlNode *prevsib = dom_object_get_node(context);
xmlNodePtr newchild, parentNode;
xmlNode *fragment, *nextsib;
xmlNode *fragment;
xmlDoc *doc;
bool afterlastchild;
int stricterror = dom_get_strict_error(context->document);
if (!prevsib->parent) {
php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
/* Spec step 1 */
parentNode = prevsib->parent;
/* Spec step 2 */
if (!parentNode) {
int stricterror = dom_get_strict_error(context->document);
php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror);
return;
}
/* Spec step 3: find first following child not in nodes; otherwise null */
xmlNodePtr viable_next_sibling = prevsib->next;
while (viable_next_sibling) {
if (!dom_is_node_in_list(nodes, nodesc, viable_next_sibling)) {
break;
}
viable_next_sibling = viable_next_sibling->next;
}
doc = prevsib->doc;
parentNode = prevsib->parent;
nextsib = prevsib->next;
afterlastchild = (nextsib == NULL);
/* Spec step 4: convert nodes into fragment */
fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
if (fragment == NULL) {
@@ -331,40 +386,9 @@ void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc)
newchild = fragment->children;
if (newchild) {
/* first node and last node are both both parameters to DOMElement::after() method so nextsib and prevsib are null. */
if (!parentNode->children) {
prevsib = nextsib = NULL;
} else if (afterlastchild) {
/*
* The new node will be inserted after last node, prevsib is last node.
* The first node is the parameter to DOMElement::after() if parentNode->children == prevsib is true
* and prevsib does not change, otherwise prevsib is parentNode->last (first node).
*/
prevsib = parentNode->children == prevsib ? prevsib : parentNode->last;
} else {
/*
* The new node will be inserted after first node, prevsib is first node.
* The first node is not the parameter to DOMElement::after() if parentNode->children == prevsib is true
* and prevsib does not change otherwise prevsib is null to mean that parentNode->children is the new node.
*/
prevsib = parentNode->children == prevsib ? prevsib : NULL;
}
/* Step 5: place fragment into the parent before viable_next_sibling */
dom_pre_insert(viable_next_sibling, parentNode, newchild, fragment);
if (prevsib) {
fragment->last->next = prevsib->next;
if (prevsib->next) {
prevsib->next->prev = fragment->last;
}
prevsib->next = newchild;
} else {
parentNode->children = newchild;
if (nextsib) {
fragment->last->next = nextsib;
nextsib->prev = fragment->last;
}
}
newchild->prev = prevsib;
dom_fragment_assign_parent_node(parentNode, fragment);
dom_reconcile_ns(doc, newchild);
}
@@ -374,17 +398,34 @@ void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc)
void dom_parent_node_before(dom_object *context, zval *nodes, int nodesc)
{
/* Spec link: https://dom.spec.whatwg.org/#dom-childnode-before */
xmlNode *nextsib = dom_object_get_node(context);
xmlNodePtr newchild, prevsib, parentNode;
xmlNode *fragment, *afternextsib;
xmlNodePtr newchild, parentNode;
xmlNode *fragment;
xmlDoc *doc;
bool beforefirstchild;
/* Spec step 1 */
parentNode = nextsib->parent;
/* Spec step 2 */
if (!parentNode) {
int stricterror = dom_get_strict_error(context->document);
php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror);
return;
}
/* Spec step 3: find first following child not in nodes; otherwise null */
xmlNodePtr viable_previous_sibling = nextsib->prev;
while (viable_previous_sibling) {
if (!dom_is_node_in_list(nodes, nodesc, viable_previous_sibling)) {
break;
}
viable_previous_sibling = viable_previous_sibling->prev;
}
doc = nextsib->doc;
prevsib = nextsib->prev;
afternextsib = nextsib->next;
parentNode = nextsib->parent;
beforefirstchild = !prevsib;
/* Spec step 4: convert nodes into fragment */
fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
if (fragment == NULL) {
@@ -394,37 +435,14 @@ void dom_parent_node_before(dom_object *context, zval *nodes, int nodesc)
newchild = fragment->children;
if (newchild) {
/* first node and last node are both both parameters to DOMElement::before() method so nextsib is null. */
if (!parentNode->children) {
nextsib = NULL;
} else if (beforefirstchild) {
/*
* The new node will be inserted before first node, nextsib is first node and afternextsib is last node.
* The first node is not the parameter to DOMElement::before() if parentNode->children == nextsib is true
* and nextsib does not change, otherwise nextsib is the last node.
*/
nextsib = parentNode->children == nextsib ? nextsib : afternextsib;
/* Step 5: if viable_previous_sibling is null, set it to the parent's first child, otherwise viable_previous_sibling's next sibling */
if (!viable_previous_sibling) {
viable_previous_sibling = parentNode->children;
} else {
/*
* The new node will be inserted before last node, prevsib is first node and nestsib is last node.
* The first node is not the parameter to DOMElement::before() if parentNode->children == prevsib is true
* but last node may be, so use prevsib->next to determine the value of nextsib, otherwise nextsib does not change.
*/
nextsib = parentNode->children == prevsib ? prevsib->next : nextsib;
viable_previous_sibling = viable_previous_sibling->next;
}
if (parentNode->children == nextsib) {
parentNode->children = newchild;
} else {
prevsib->next = newchild;
}
fragment->last->next = nextsib;
if (nextsib) {
nextsib->prev = fragment->last;
}
newchild->prev = prevsib;
/* Step 6: place fragment into the parent after viable_previous_sibling */
dom_pre_insert(viable_previous_sibling, parentNode, newchild, fragment);
dom_fragment_assign_parent_node(parentNode, fragment);
dom_reconcile_ns(doc, newchild);

View File

@@ -8,84 +8,84 @@ $doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->before($target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "1 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->before($target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "2 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->before($doc->documentElement->lastChild);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "3 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->before($doc->documentElement->firstChild);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "4 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->before($target, $doc->documentElement->lastChild);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "5 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->before($doc->documentElement->lastChild, $target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "6 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->before($target, $doc->documentElement->firstChild);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "7 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->before($doc->documentElement->firstChild, $target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "8 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->before('bar','baz');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "9 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->before('bar','baz');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "10 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->before($target, 'bar','baz');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "11 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->before('bar', $target, 'baz');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "12 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->before('bar', 'baz', $target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "13 ", $doc->saveXML($doc->documentElement).PHP_EOL;
@@ -93,19 +93,19 @@ $doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->before($target, 'bar','baz');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "14 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->before('bar', $target, 'baz');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "15 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->before('bar', 'baz', $target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "16 ", $doc->saveXML($doc->documentElement).PHP_EOL;
@@ -113,21 +113,21 @@ $doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->before('bar', $target, $doc->documentElement->lastChild);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "17 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->before($target, 'bar', $doc->documentElement->lastChild);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "18 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->before($target, $doc->documentElement->lastChild, 'bar');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "19 ", $doc->saveXML($doc->documentElement).PHP_EOL;
@@ -136,43 +136,43 @@ $doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->before('bar', $doc->documentElement->firstChild, $target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "20 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->before($doc->documentElement->firstChild, 'bar', $target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "21 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->before($doc->documentElement->firstChild, $target, 'bar');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "22 ", $doc->saveXML($doc->documentElement).PHP_EOL;
?>
--EXPECTF--
<a>foo<last/></a>
<a>foo<last/></a>
<a><last/>foo</a>
<a>foo<last/></a>
<a>foo<last/></a>
<a><last/>foo</a>
<a><last/>foo</a>
<a>foo<last/></a>
<a>barbazfoo<last/></a>
<a>foobarbaz<last/></a>
<a>foobarbaz<last/></a>
<a>barfoobaz<last/></a>
<a>barbazfoo<last/></a>
<a>foo<last/>barbaz</a>
<a>foobar<last/>baz</a>
<a>foobarbaz<last/></a>
<a>barfoo<last/></a>
<a>foobar<last/></a>
<a>foo<last/>bar</a>
<a>barfoo<last/></a>
<a>foobar<last/></a>
<a>foo<last/>bar</a>
1 <a>foo<last/></a>
2 <a>foo<last/></a>
3 <a><last/>foo</a>
4 <a>foo<last/></a>
5 <a>foo<last/></a>
6 <a><last/>foo</a>
7 <a><last/>foo</a>
8 <a>foo<last/></a>
9 <a>barbazfoo<last/></a>
10 <a>foobarbaz<last/></a>
11 <a>foobarbaz<last/></a>
12 <a>barfoobaz<last/></a>
13 <a>barbazfoo<last/></a>
14 <a>foo<last/>barbaz</a>
15 <a>foobar<last/>baz</a>
16 <a>foobarbaz<last/></a>
17 <a>barfoo<last/></a>
18 <a>foobar<last/></a>
19 <a>foo<last/>bar</a>
20 <a>barfoo<last/></a>
21 <a>foobar<last/></a>
22 <a>foo<last/>bar</a>

View File

@@ -8,84 +8,84 @@ $doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->after($target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "1 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->after($target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "2 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->after($doc->documentElement->lastChild);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "3 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->after($doc->documentElement->firstChild);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "4 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->after($target, $doc->documentElement->lastChild);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "5 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->after($doc->documentElement->lastChild, $target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "6 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->after($target, $doc->documentElement->firstChild);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "7 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->after($doc->documentElement->firstChild, $target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "8 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->after('bar','baz');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "9 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->after('bar','baz');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "10 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->after($target, 'bar','baz');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "11 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->after('bar', $target, 'baz');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "12 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->after('bar', 'baz', $target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "13 ", $doc->saveXML($doc->documentElement).PHP_EOL;
@@ -93,19 +93,19 @@ $doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->after($target, 'bar','baz');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "14 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->after('bar', $target, 'baz');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "15 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->after('bar', 'baz', $target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "16 ", $doc->saveXML($doc->documentElement).PHP_EOL;
@@ -113,21 +113,21 @@ $doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->after('bar', $target, $doc->documentElement->lastChild);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "17 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->after($target, 'bar', $doc->documentElement->lastChild);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "18 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->firstChild;
$target->after($target, $doc->documentElement->lastChild, 'bar');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "19 ", $doc->saveXML($doc->documentElement).PHP_EOL;
@@ -136,43 +136,43 @@ $doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->after('bar', $doc->documentElement->firstChild, $target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "20 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->after($doc->documentElement->firstChild, 'bar', $target);
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "21 ", $doc->saveXML($doc->documentElement).PHP_EOL;
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->after($doc->documentElement->firstChild, $target, 'bar');
echo $doc->saveXML($doc->documentElement).PHP_EOL;
echo "22 ", $doc->saveXML($doc->documentElement).PHP_EOL;
?>
--EXPECTF--
<a>foo<last/></a>
<a>foo<last/></a>
<a>foo<last/></a>
<a><last/>foo</a>
<a>foo<last/></a>
<a><last/>foo</a>
<a><last/>foo</a>
<a>foo<last/></a>
<a>foobarbaz<last/></a>
<a>foo<last/>barbaz</a>
<a>foobarbaz<last/></a>
<a>barfoobaz<last/></a>
<a>barbazfoo<last/></a>
<a>foo<last/>barbaz</a>
<a>foobar<last/>baz</a>
<a>foobarbaz<last/></a>
<a>barfoo<last/></a>
<a>foobar<last/></a>
<a>foo<last/>bar</a>
<a>barfoo<last/></a>
<a>foobar<last/></a>
<a>foo<last/>bar</a>
1 <a>foo<last/></a>
2 <a>foo<last/></a>
3 <a>foo<last/></a>
4 <a><last/>foo</a>
5 <a>foo<last/></a>
6 <a><last/>foo</a>
7 <a><last/>foo</a>
8 <a>foo<last/></a>
9 <a>foobarbaz<last/></a>
10 <a>foo<last/>barbaz</a>
11 <a>foobarbaz<last/></a>
12 <a>barfoobaz<last/></a>
13 <a>barbazfoo<last/></a>
14 <a>foo<last/>barbaz</a>
15 <a>foobar<last/>baz</a>
16 <a>foobarbaz<last/></a>
17 <a>barfoo<last/></a>
18 <a>foobar<last/></a>
19 <a>foo<last/>bar</a>
20 <a>barfoo<last/></a>
21 <a>foobar<last/></a>
22 <a>foo<last/>bar</a>

View File

@@ -0,0 +1,120 @@
--TEST--
Bug #80602 (Segfault when using DOMChildNode::before()) - use-after-free variation
--FILE--
<?php
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
$target->before('bar', $doc->documentElement->firstChild, 'baz');
echo $doc->saveXML($doc->documentElement), "\n";
var_dump($target);
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/></a>');
$target = $doc->documentElement->lastChild;
// Note: after instead of before
$target->after('bar', $doc->documentElement->firstChild, 'baz');
echo $doc->saveXML($doc->documentElement), "\n";
var_dump($target);
?>
--EXPECTF--
<a>barfoobaz<last/></a>
object(DOMElement)#3 (23) {
["schemaTypeInfo"]=>
NULL
["tagName"]=>
string(4) "last"
["firstElementChild"]=>
NULL
["lastElementChild"]=>
NULL
["childElementCount"]=>
int(0)
["previousElementSibling"]=>
NULL
["nextElementSibling"]=>
NULL
["nodeName"]=>
string(4) "last"
["nodeValue"]=>
string(0) ""
["nodeType"]=>
int(1)
["parentNode"]=>
string(22) "(object value omitted)"
["childNodes"]=>
string(22) "(object value omitted)"
["firstChild"]=>
NULL
["lastChild"]=>
NULL
["previousSibling"]=>
string(22) "(object value omitted)"
["nextSibling"]=>
NULL
["attributes"]=>
string(22) "(object value omitted)"
["ownerDocument"]=>
string(22) "(object value omitted)"
["namespaceURI"]=>
NULL
["prefix"]=>
string(0) ""
["localName"]=>
string(4) "last"
["baseURI"]=>
string(%d) %s
["textContent"]=>
string(0) ""
}
<a><last/>barfoobaz</a>
object(DOMElement)#2 (23) {
["schemaTypeInfo"]=>
NULL
["tagName"]=>
string(4) "last"
["firstElementChild"]=>
NULL
["lastElementChild"]=>
NULL
["childElementCount"]=>
int(0)
["previousElementSibling"]=>
NULL
["nextElementSibling"]=>
NULL
["nodeName"]=>
string(4) "last"
["nodeValue"]=>
string(0) ""
["nodeType"]=>
int(1)
["parentNode"]=>
string(22) "(object value omitted)"
["childNodes"]=>
string(22) "(object value omitted)"
["firstChild"]=>
NULL
["lastChild"]=>
NULL
["previousSibling"]=>
NULL
["nextSibling"]=>
string(22) "(object value omitted)"
["attributes"]=>
string(22) "(object value omitted)"
["ownerDocument"]=>
string(22) "(object value omitted)"
["namespaceURI"]=>
NULL
["prefix"]=>
string(0) ""
["localName"]=>
string(4) "last"
["baseURI"]=>
string(%d) %s
["textContent"]=>
string(0) ""
}

View File

@@ -0,0 +1,33 @@
--TEST--
Bug #80602 (Segfault when using DOMChildNode::before()) - after text merge variation
--FILE--
<?php
$doc = new \DOMDocument();
$doc->loadXML('<a>foo<last/>bar</a>');
$foo = $doc->firstChild->firstChild;
$bar = $doc->firstChild->lastChild;
$foo->after($bar);
var_dump($doc->saveXML());
$foo->nodeValue = "x";
var_dump($doc->saveXML());
$bar->nodeValue = "y";
var_dump($doc->saveXML());
?>
--EXPECT--
string(43) "<?xml version="1.0"?>
<a>foobar<last/></a>
"
string(41) "<?xml version="1.0"?>
<a>xbar<last/></a>
"
string(39) "<?xml version="1.0"?>
<a>xy<last/></a>
"

View File

@@ -0,0 +1,67 @@
--TEST--
GH-11288 (Error: Couldn't fetch DOMElement introduced in 8.2.6, 8.1.19)
--FILE--
<?php
$html = <<<HTML
<!DOCTYPE HTML>
<html>
<span class="unwrap_me"><i><span class="foo">Lorem</span></i><span class="foo">ipsum</span></span>
</html>
HTML;
$dom = new DOMDocument();
$dom->loadHTML($html);
$spans = iterator_to_array($dom->getElementsByTagName('span')->getIterator());
foreach ($spans as $span) {
if ('unwrap_me' === $span->getAttribute('class')) {
$fragment = $dom->createDocumentFragment();
$fragment->append(...$span->childNodes);
$span->parentNode?->replaceChild($fragment, $span);
}
}
var_dump(str_replace("\n", "", $dom->saveHTML()));
$html = <<<HTML
<!DOCTYPE HTML>
<html>
<span class="unwrap_me"><i><span class="foo">Lorem</span></i><span class="foo">ipsum</span></span>
</html>
HTML;
$dom = new DOMDocument();
$dom->loadHTML($html);
$spans = iterator_to_array($dom->getElementsByTagName('span')->getIterator());
foreach ($spans as $span) {
if ('unwrap_me' === $span->getAttribute('class')) {
$span->replaceWith(...$span->childNodes);
}
}
var_dump(str_replace("\n", "", $dom->saveHTML()));
$html = <<<HTML
<!DOCTYPE HTML>
<html>
<span class="unwrap_me"><i><span class="foo">Lorem</span></i><span class="foo">ipsum</span></span>
</html>
HTML;
$dom = new DOMDocument();
$dom->loadHTML($html);
$spans = iterator_to_array($dom->getElementsByTagName('span')->getIterator());
foreach ($spans as $span) {
if ('unwrap_me' === $span->getAttribute('class')) {
$span->replaceWith('abc');
}
}
var_dump(str_replace("\n", "", $dom->saveHTML()));
?>
--EXPECT--
string(108) "<!DOCTYPE HTML><html><body><i><span class="foo">Lorem</span></i><span class="foo">ipsum</span></body></html>"
string(108) "<!DOCTYPE HTML><html><body><i><span class="foo">Lorem</span></i><span class="foo">ipsum</span></body></html>"
string(44) "<!DOCTYPE HTML><html><body>abc</body></html>"

View File

@@ -0,0 +1,28 @@
--TEST--
GH-11289 (DOMException: Not Found Error introduced in 8.2.6, 8.1.19)
--FILE--
<?php
$html = <<<HTML
<!DOCTYPE HTML>
<html>
<body>
<div></div>
</body>
</html>
HTML;
$dom = new DOMDocument();
$dom->loadHTML($html);
$divs = iterator_to_array($dom->getElementsByTagName('div')->getIterator());
foreach ($divs as $div) {
$fragment = $dom->createDocumentFragment();
$fragment->appendXML('<p>Hi!</p>');
$div->replaceWith(...$fragment->childNodes);
}
var_dump(str_replace("\n", "", $dom->saveHTML()));
?>
--EXPECT--
string(55) "<!DOCTYPE HTML><html><body> <p>Hi!</p></body></html>"

View File

@@ -0,0 +1,27 @@
--TEST--
GH-11290 (DOMElement::replaceWith causes crash)
--FILE--
<?php
$html = <<<HTML
<!DOCTYPE HTML>
<html>
<body>
<p><span class="unwrap_me">Lorem</span><span class="unwrap_me">ipsum</span><span class="unwrap_me">dolor</span></p>
</body>
</html>
HTML;
$dom = new DOMDocument();
$dom->loadHTML($html);
$spans = iterator_to_array($dom->getElementsByTagName('span')->getIterator());
foreach ($spans as $span) {
if ('unwrap_me' === $span->getAttribute('class')) {
$span->replaceWith(...$span->childNodes);
}
}
var_dump(str_replace("\n", "", $dom->saveHTML()));
?>
--EXPECT--
string(67) "<!DOCTYPE HTML><html><body> <p>Loremipsumdolor</p></body></html>"

20
ext/dom/tests/gh9142.phpt Normal file
View File

@@ -0,0 +1,20 @@
--TEST--
GH-9142 (DOMChildNode replaceWith() double-free error when replacing elements not separated by any whitespace)
--FILE--
<?php
$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->replaceWith($dom->createElement('p', $var->nodeValue));
}
var_dump($dom->saveHTML());
?>
--EXPECT--
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>
"