diff --git a/ext/dom/node.c b/ext/dom/node.c index 49e400ef5302..867d166edb47 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -1513,6 +1513,10 @@ PHP_METHOD(DOMNode, cloneNode) if (clone_document && private_data != NULL) { php_dom_private_data_destroy(private_data); } + if (instanceof_function(intern->std.ce, dom_modern_node_class_entry)) { + php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true); + RETURN_THROWS(); + } RETURN_FALSE; } diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 445eacdfa198..ed300185eec1 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -663,9 +663,11 @@ static zend_object *dom_objects_store_clone_obj(zend_object *zobject) /* {{{ */ xmlNodePtr cloned_node = dom_clone_node(php_dom_ns_mapper_from_private(private_data), node, node->doc, true); if (cloned_node != NULL) { dom_update_refcount_after_clone(intern, node, clone, cloned_node); - } - if (private_data != NULL) { - clone->document->private_data = php_dom_libxml_private_data_header(private_data); + if (private_data != NULL) { + clone->document->private_data = php_dom_libxml_private_data_header(private_data); + } + } else if (private_data != NULL && (node->type == XML_DOCUMENT_NODE || node->type == XML_HTML_DOCUMENT_NODE)) { + php_dom_private_data_destroy(private_data); } } } diff --git a/ext/dom/tests/modern/xml/gh25268_declarations.phpt b/ext/dom/tests/modern/xml/gh25268_declarations.phpt new file mode 100644 index 000000000000..ce814f2f7c4b --- /dev/null +++ b/ext/dom/tests/modern/xml/gh25268_declarations.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-25268 (NULL php_libxml_ref_obj dereference in dom_objects_store_clone_obj when cloning DTD declarations) +--EXTENSIONS-- +dom +--FILE-- +]>'); + +foreach ([$dom->doctype->entities->getNamedItem("e"), $dom->doctype->childNodes[0]] as $decl) { + $clone = clone $decl; + try { + var_dump($clone->nodeName); + } catch (DOMException $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; + } + try { + var_dump($decl->cloneNode()); + } catch (DOMException $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; + } +} +?> +--EXPECT-- +DOMException: Invalid State Error +DOMException: Invalid State Error +DOMException: Invalid State Error +DOMException: Invalid State Error