]> granicus.if.org Git - php/commitdiff
Fix #63575: Root elements are not properly cloned
authorChristoph M. Becker <cmbecker69@gmx.de>
Thu, 23 Apr 2020 14:16:58 +0000 (16:16 +0200)
committerChristoph M. Becker <cmbecker69@gmx.de>
Wed, 17 Jun 2020 14:48:50 +0000 (16:48 +0200)
Cloning of root elements has to preserve that property, so they require
some special treatment.

NEWS
ext/simplexml/simplexml.c
ext/simplexml/tests/bug39662.phpt
ext/simplexml/tests/bug63575.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index db10e1be45470937f32a50ec45b4315264a84ba7..3732e9946db846c579b245191d951c9403967d14 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -154,6 +154,7 @@ PHP                                                                        NEWS
 - SimpleXML:
   . Fixed bug #75245 (Don't set content of elements with only whitespaces).
     (eriklundin)
+  . Fixed bug #63575 (Root elements are not properly cloned). (cmb)
 
 - sodium:
   . Fixed bug #77646 (sign_detached() strings not terminated). (Frank)
index 20e20e3a2b81c5ec3b2976130a8b028f25ee71fc..8d8a47f73ebba0bc32887f2a77f2ecef27297de0 100644 (file)
@@ -2035,12 +2035,20 @@ sxe_object_clone(zend_object *object)
        php_sxe_object *clone;
        xmlNodePtr nodep = NULL;
        xmlDocPtr docp = NULL;
+       zend_bool is_root_element = sxe->node && sxe->node->node && sxe->node->node->parent
+               && (sxe->node->node->parent->type == XML_DOCUMENT_NODE || sxe->node->node->parent->type == XML_HTML_DOCUMENT_NODE);
 
        clone = php_sxe_object_new(sxe->zo.ce, sxe->fptr_count);
-       clone->document = sxe->document;
-       if (clone->document) {
-               clone->document->refcount++;
-               docp = clone->document->ptr;
+
+       if (is_root_element) {
+               docp = xmlCopyDoc(sxe->document->ptr, 1);
+               php_libxml_increment_doc_ref((php_libxml_node_object *)clone, docp);
+       } else {
+               clone->document = sxe->document;
+               if (clone->document) {
+                       clone->document->refcount++;
+                       docp = clone->document->ptr;
+               }
        }
 
        clone->iter.isprefix = sxe->iter.isprefix;
@@ -2053,7 +2061,11 @@ sxe_object_clone(zend_object *object)
        clone->iter.type = sxe->iter.type;
 
        if (sxe->node) {
-               nodep = xmlDocCopyNode(sxe->node->node, docp, 1);
+               if (is_root_element) {
+                       nodep = xmlDocGetRootElement(docp);
+               } else {
+                       nodep = xmlDocCopyNode(sxe->node->node, docp, 1);
+               }
        }
 
        php_libxml_increment_node_ptr((php_libxml_node_object *)clone, nodep, NULL);
index 5dc2b99a924810183395108ff8aa095fb04bdafe..343aeef7036fdec7fe78d2e4463935d019cc5b0d 100644 (file)
@@ -23,7 +23,9 @@ object(SimpleXMLElement)#%d (0) {
 }
 object(SimpleXMLElement)#%d (0) {
 }
-string(15) "<test>
+string(%d) "<?xml version="1.0" encoding="utf-8"?>
+<test>
 
-</test>"
+</test>
+"
 Done
diff --git a/ext/simplexml/tests/bug63575.phpt b/ext/simplexml/tests/bug63575.phpt
new file mode 100644 (file)
index 0000000..0947ea6
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+Bug #63575 (Root elements are not properly cloned)
+--SKIPIF--
+<?php
+if (!extension_loaded('simplexml')) die('skip simplexml extension not available');
+?>
+--FILE--
+<?php
+$xml = '<a><b></b></a>';
+
+$o1 = new SimpleXMlElement($xml);
+$o2 = clone $o1;
+
+$r = current($o2->xpath('/a'));
+$r->addChild('c', new SimpleXMlElement('<c></c>'));
+
+echo $o1->asXML(), PHP_EOL, $o2->asXML();
+?>
+--EXPECT--
+<?xml version="1.0"?>
+<a><b/></a>
+
+<?xml version="1.0"?>
+<a><b/><c/></a>