From a2deee2141ef2e856b416bc8851b9b7744da78af Mon Sep 17 00:00:00 2001
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date: Sat, 14 Jan 2023 16:15:01 +0100
Subject: [PATCH 1/2] Fix bug #69168: DomNode::getNodePath() returns invalid
path
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.
This was reported in bug #49634, and was fixed by always copying the
node (and later re-fixed in bug #70078).
The original fix is not entirely correct unfortunately because of the
following two main reasons:
- modifications to the node will only modify the copy, and not the original
- accesses to the parent, path, ... will not work
This patch fixes it properly by only copying the node if it origins from
a document other than the main document.
---
ext/xsl/xsltprocessor.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
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);
From 9644b932bf9be6d35981f8b678afd3e48fccc5f9 Mon Sep 17 00:00:00 2001
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date: Sat, 14 Jan 2023 16:21:35 +0100
Subject: [PATCH 2/2] =?UTF-8?q?Add=20a=20regression=20test=20for=20bug?=
=?UTF-8?q?=C2=A0#69168?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This additionally tests for modifications of nodes.
Co-authored-by: juha.ikavalko@agentit.fi
---
ext/xsl/tests/bug69168.phpt | 43 +++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 ext/xsl/tests/bug69168.phpt
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"