From 91f4f15f1687d145f336ad6c1d6ca178bda33920 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 15 Jun 2020 03:22:41 +0200 Subject: [PATCH] Fix #79700: Bad performance with namespaced nodes due to wrong libxml assumption. --- ext/dom/php_dom.c | 28 -------------------- ext/dom/php_dom.h | 1 - ext/dom/tests/bug79700.phpt | 52 +++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 29 deletions(-) create mode 100644 ext/dom/tests/bug79700.phpt diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 9dc50ac28773d..58fe7b61c9417 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -1361,33 +1361,6 @@ void dom_normalize (xmlNodePtr nodep) } /* }}} end dom_normalize */ - -/* {{{ void dom_set_old_ns(xmlDoc *doc, xmlNs *ns) */ -void dom_set_old_ns(xmlDoc *doc, xmlNs *ns) { - xmlNs *cur; - - if (doc == NULL) - return; - - if (doc->oldNs == NULL) { - doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (doc->oldNs == NULL) { - return; - } - memset(doc->oldNs, 0, sizeof(xmlNs)); - doc->oldNs->type = XML_LOCAL_NAMESPACE; - doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE); - doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml"); - } - - cur = doc->oldNs; - while (cur->next != NULL) { - cur = cur->next; - } - cur->next = ns; -} -/* }}} end dom_set_old_ns */ - void dom_reconcile_ns(xmlDocPtr doc, xmlNodePtr nodep) /* {{{ */ { xmlNsPtr nsptr, nsdftptr, curns, prevns = NULL; @@ -1407,7 +1380,6 @@ void dom_reconcile_ns(xmlDocPtr doc, xmlNodePtr nodep) /* {{{ */ } else { prevns->next = nsdftptr; } - dom_set_old_ns(doc, curns); curns = prevns; } } diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index 7a0a5e7d72e5f..abf88282dddfc 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -108,7 +108,6 @@ void php_dom_throw_error_with_message(int error_code, char *error_message, int s void node_list_unlink(xmlNodePtr node); int dom_check_qname(char *qname, char **localname, char **prefix, int uri_len, int name_len); xmlNsPtr dom_get_ns(xmlNodePtr node, char *uri, int *errorcode, char *prefix); -void dom_set_old_ns(xmlDoc *doc, xmlNs *ns); void dom_reconcile_ns(xmlDocPtr doc, xmlNodePtr nodep); xmlNsPtr dom_get_nsdecl(xmlNode *node, xmlChar *localName); void dom_normalize (xmlNodePtr nodep); diff --git a/ext/dom/tests/bug79700.phpt b/ext/dom/tests/bug79700.phpt new file mode 100644 index 0000000000000..6977734054401 --- /dev/null +++ b/ext/dom/tests/bug79700.phpt @@ -0,0 +1,52 @@ +--TEST-- +dom: Can we go without dom_set_old_ns? +--FILE-- +appendChild($element = $dom->createElement('xml:xml')); +$element->setAttribute('xmlns', 'http://www.w3.org/2000/xmlns/'); +$element->setAttribute('xmlns:xml', 'http://www.w3.org/XML/1998/namespace'); +echo $dom->saveXML(); + +$html = new DOMDocument(); +$element->setAttribute('xmlns', 'http://www.w3.org/2000/xmlns/'); +$element->setAttribute('xmlns:xml', 'http://www.w3.org/XML/1998/namespace'); +$html->appendChild($element = $html->createElement('xml:html')); + +echo $html->saveHTML(); + +$dom->documentElement->appendChild($dom->importNode($element)); + +echo $dom->saveXML(); + +// now test performance of 10000 namespaced elements. second run should not take more than 3x (safety margin) as long as first time. + +$dom = new DOMDocument(); +$root = $dom->createElementNS('http://www.w3.org/2000/xhtml', 'html'); +$dom->appendChild($root); + +$s = microtime(true); +for ($i = 0; $i < 10000; $i++) { + $element = $dom->createElementNS('http://www.w3.org/2000/xhtml', 'p', 'Hello World'); + $root->appendChild($element); +} +$firstRun = microtime(true) - $s; + +$s = microtime(true); +for ($i = 0; $i < 10000; $i++) { + $element = $dom->createElementNS('http://www.w3.org/2000/xhtml', 'p', 'Hello World'); + $root->appendChild($element); +} +$secondRun = microtime(true) - $s; + +if ($firstRun * 3 < $secondRun) { + echo "FAIL; second run took more than 3 times as long as first run. Performance should be linear\n"; +} + +--EXPECTF-- + + + + +