Skip to content

Commit 65efb49

Browse files
committed
Fix parent check and viable next sibling search for replaceWith
1 parent bbf29b7 commit 65efb49

File tree

3 files changed

+27
-18
lines changed

3 files changed

+27
-18
lines changed

ext/dom/parentnode.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -545,21 +545,39 @@ void dom_child_node_remove(dom_object *context)
545545

546546
void dom_child_replace_with(dom_object *context, zval *nodes, int nodesc)
547547
{
548+
/* Spec link: https://dom.spec.whatwg.org/#dom-childnode-replacewith*/
549+
548550
xmlNodePtr child = dom_object_get_node(context);
551+
552+
/* Spec step 1 */
549553
xmlNodePtr parentNode = child->parent;
554+
/* Spec step 2 */
555+
if (!parentNode) {
556+
return;
557+
}
550558

551559
int stricterror = dom_get_strict_error(context->document);
552560
if (UNEXPECTED(dom_child_removal_preconditions(child, stricterror) != SUCCESS)) {
553561
return;
554562
}
555563

556-
xmlNodePtr insertion_point = child->next;
564+
/* Spec step 3: find first following child not in nodes; otherwise null */
565+
xmlNodePtr viable_next_sibling = child->next;
566+
while (viable_next_sibling) {
567+
if (!dom_is_node_in_list(nodes, nodesc, viable_next_sibling)) {
568+
break;
569+
}
570+
viable_next_sibling = viable_next_sibling->next;
571+
}
557572

573+
/* Spec step 4: convert nodes into fragment */
558574
xmlNodePtr fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
559575
if (UNEXPECTED(fragment == NULL)) {
560576
return;
561577
}
562578

579+
/* Spec step 5: perform the replacement */
580+
563581
xmlNodePtr newchild = fragment->children;
564582
xmlDocPtr doc = parentNode->doc;
565583

@@ -571,7 +589,7 @@ void dom_child_replace_with(dom_object *context, zval *nodes, int nodesc)
571589
if (newchild) {
572590
xmlNodePtr last = fragment->last;
573591

574-
dom_pre_insert(insertion_point, parentNode, newchild, fragment);
592+
dom_pre_insert(viable_next_sibling, parentNode, newchild, fragment);
575593

576594
dom_fragment_assign_parent_node(parentNode, fragment);
577595
dom_reconcile_ns_list(doc, newchild, last);

ext/dom/tests/replaceWith_no_parent.phpt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ $test->replaceWith($child);
2020
echo $doc->saveXML();
2121
echo $doc->saveXML($test);
2222
?>
23-
--EXPECTF--
24-
Fatal error: Uncaught DOMException: Not Found Error in %s:%d
25-
Stack trace:
26-
#0 %s(%d): DOMElement->replaceWith(Object(DOMElement))
27-
#1 {main}
28-
thrown in %s on line %d
23+
--EXPECT--
24+
<?xml version="1.0"?>
25+
<container>
26+
<child/>
27+
</container>
28+
<foo/>

ext/dom/tests/replaceWith_non_viable_next_sibling.phpt

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,5 @@ echo $doc->saveXML();
3232
</container>
3333
<?xml version="1.0"?>
3434
<container>
35-
35+
<alone/>
3636
</container>
37-
38-
=================================================================
39-
==1151863==ERROR: LeakSanitizer: detected memory leaks
40-
41-
Direct leak of 120 byte(s) in 1 object(s) allocated from:
42-
#0 0x7fc122ee1369 in __interceptor_malloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:69
43-
#1 0x7fc122d02bd0 in xmlNewNodeEatName /home/niels/libxml2/tree.c:2317
44-
45-
SUMMARY: AddressSanitizer: 120 byte(s) leaked in 1 allocation(s).

0 commit comments

Comments
 (0)