diff --git a/ext/dom/node.c b/ext/dom/node.c
index a42dfedc32a5..49e400ef5302 100644
--- a/ext/dom/node.c
+++ b/ext/dom/node.c
@@ -931,6 +931,9 @@ static void dom_node_insert_before_legacy(zval *return_value, zval *ref, dom_obj
php_dom_throw_error(NOT_FOUND_ERR, stricterror);
RETURN_FALSE;
}
+ if (refp == child) {
+ refp = child->next;
+ }
}
if (child->doc == NULL && parentp->doc != NULL) {
@@ -940,7 +943,7 @@ static void dom_node_insert_before_legacy(zval *return_value, zval *ref, dom_obj
php_libxml_invalidate_node_list_cache(intern->document);
- if (ref != NULL) {
+ if (refp != NULL) {
if (child->parent != NULL) {
xmlUnlinkNode(child);
}
diff --git a/ext/dom/tests/gh23365.phpt b/ext/dom/tests/gh23365.phpt
new file mode 100644
index 000000000000..bc283b0659d3
--- /dev/null
+++ b/ext/dom/tests/gh23365.phpt
@@ -0,0 +1,53 @@
+--TEST--
+GH-23365 (DOMNode::insertBefore($n, $n) drops the node and leaves a self-referencing sibling list)
+--CREDITS--
+Alexandre Daubois
+--EXTENSIONS--
+dom
+--FILE--
+loadXML('text');
+$root = $doc->documentElement;
+
+$text = $root->firstChild;
+var_dump($root->insertBefore($text, $text) === $text);
+var_dump($root->childNodes->length);
+var_dump($text->parentNode === $root, $text->nextSibling === $text, $text->previousSibling === $text);
+
+$child = $root->lastChild;
+var_dump($root->insertBefore($child, $child) === $child);
+var_dump($root->childNodes->length);
+
+echo $doc->saveXML($root), PHP_EOL;
+
+$doc2 = new DOMDocument();
+$doc2->loadXML('');
+$el = $doc2->documentElement;
+$attr = $el->getAttributeNode('a');
+var_dump($el->insertBefore($attr, $attr) === $attr);
+echo $doc2->saveXML($el), PHP_EOL;
+
+$doc3 = new DOMDocument();
+$root3 = $doc3->appendChild($doc3->createElement('root'));
+$root3->appendChild($doc3->createTextNode('A'));
+$t = $root3->appendChild($doc3->createTextNode('B'));
+$root3->insertBefore($t, $t);
+$root3->appendChild($t);
+echo $doc3->saveXML($root3), PHP_EOL;
+unset($t, $root3, $doc3);
+echo "done", PHP_EOL;
+?>
+--EXPECT--
+bool(true)
+int(2)
+bool(true)
+bool(false)
+bool(false)
+bool(true)
+int(2)
+text
+bool(true)
+
+AB
+done