diff --git a/ext/xsl/tests/bug69168.phpt b/ext/xsl/tests/bug69168.phpt new file mode 100644 index 0000000000000..41fc3aafd8209 --- /dev/null +++ b/ext/xsl/tests/bug69168.phpt @@ -0,0 +1,43 @@ +--TEST-- +bug #69168 (DomNode::getNodePath() returns invalid path) +--EXTENSIONS-- +xsl +--FILE-- +bobjoe +EOB; +$xsl = << + + + +
+
+
+
+EOB; + +function getPath($input){ + $input[0]->nodeValue .= 'a'; + return $input[0]->getNodePath() . ' = ' . $input[0]->nodeValue; +} + +$proc = new XSLTProcessor(); +$proc->registerPHPFunctions(); +$xslDoc = new DOMDocument(); +$xslDoc->loadXML($xsl); +@$proc->importStyleSheet($xslDoc); +$xmlDoc = new DOMDocument(); +$xmlDoc->loadXML($xml); +echo @$proc->transformToXML($xmlDoc); + +// Tests modification of the nodes +var_dump($xmlDoc->firstChild->firstChild->firstChild->getNodePath()); +var_dump($xmlDoc->firstChild->firstChild->firstChild->nodeValue); +?> +--EXPECT-- + +/allusers/user[1]/uid = boba
/allusers/user[2]/uid = joea
+string(21) "/allusers/user[1]/uid" +string(4) "boba" diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c index c62c0a13ceaec..8dbe6b27a113b 100644 --- a/ext/xsl/xsltprocessor.c +++ b/ext/xsl/xsltprocessor.c @@ -194,7 +194,19 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t node->parent = nsparent; node->ns = curns; } else { - node = xmlDocCopyNode(node, domintern->document->ptr, 1); + /** + * Upon freeing libxslt's context, every document which is not the *main* document will be freed by libxslt. + * If a node of a document which is *not the main* document gets returned to userland, we'd free the node twice: + * first by the cleanup of the xslt context, and then by our own refcounting mechanism. + * To prevent this, we'll take a copy if the node is not from the main document. + * It is important that we do not copy the node unconditionally, because that means that: + * - modifications to the node will only modify the copy, and not the original + * - accesses to the parent, path, ... will not work + */ + xsltTransformContextPtr transform_ctxt = (xsltTransformContextPtr) ctxt->context->extra; + if (node->doc != transform_ctxt->document->doc) { + node = xmlDocCopyNode(node, domintern->document->ptr, 1); + } } php_dom_create_object(node, &child, domintern);