[PHP-CVS] [php-src] master: Merge branch 'PHP-8.5'
[email protected] (Ilia Alshanetsky)
| Newsgroups | php.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: Ilia Alshanetsky (iliaal)
Date: 2026-08-17T06:53:52-04:00
Commit: https://github.com/php/php-src/commit/d72a9106c5a2355478b95a178d3095909e660e99
Raw diff: https://github.com/php/php-src/commit/d72a9106c5a2355478b95a178d3095909e660e99.diff
Merge branch 'PHP-8.5'
* PHP-8.5:
Fix DOMXPath crash wrapping a foreign node after a nodeset callback
Changed paths:
A ext/dom/tests/xpath_php_function_foreign_doc.phpt
M NEWS
M ext/dom/xpath.c
Diff:
diff --git a/NEWS b/NEWS
index 8e7950150646..a0c4359f4a09 100644
--- a/NEWS
+++ b/NEWS
@@ -19,6 +19,8 @@ PHP NEWS
DOMDocument::xinclude()). (David Carlier)
. Fixed a use-after-free when cloning a DOMNameSpaceNode after
DOMDocument::xinclude(). (iliaal)
+ . Fixed a crash in DOMXPath when a php:function callback receives a nodeset
+ and a later callback returns a node from another document. (iliaal)
- PDO_PGSQL:
. Fixed several lazy fetch (PDO::ATTR_PREFETCH => 0) defects: an infinite
diff --git a/ext/dom/tests/xpath_php_function_foreign_doc.phpt b/ext/dom/tests/xpath_php_function_foreign_doc.phpt
new file mode 100644
index 000000000000..4e4b2b2c2822
--- /dev/null
+++ b/ext/dom/tests/xpath_php_function_foreign_doc.phpt
@@ -0,0 +1,40 @@
+--TEST--
+DOMXPath: php:function nodeset args plus a foreign-document return must not treat arrays as DOM objects
+--EXTENSIONS--
+dom
+--FILE--
+<?php
+$doc1 = new DOMDocument();
+$doc1->loadXML('<root><a>1</a></root>');
+$doc2 = new DOMDocument();
+$doc2->loadXML('<root><b>2</b></root>');
+
+$xp = new DOMXPath($doc1);
+$xp->registerNamespace('php', 'http://php.net/xpath');
+$xp->registerPhpFunctions();
+
+function uses_nodeset($nodes) {
+ return true;
+}
+
+function foreign() {
+ global $doc2;
+ return $doc2->documentElement;
+}
+
+$xp->query('//a[php:function("uses_nodeset", //a)]');
+$res = $xp->query('php:function("foreign")');
+echo "count: ";
+var_dump($res->length);
+$n = $res->item(0);
+echo "name: ";
+var_dump($n->nodeName);
+echo "owner is doc2: ";
+var_dump($n->ownerDocument === $doc2);
+echo "done\n";
+?>
+--EXPECT--
+count: int(1)
+name: string(4) "root"
+owner is doc2: bool(true)
+done
diff --git a/ext/dom/xpath.c b/ext/dom/xpath.c
index dc9e1b852fae..a35d343b50d9 100644
--- a/ext/dom/xpath.c
+++ b/ext/dom/xpath.c
@@ -33,6 +33,25 @@
#ifdef LIBXML_XPATH_ENABLED
+static dom_object *dom_xpath_intern_from_entry(zval *entry, xmlDocPtr doc)
+{
+ if (Z_TYPE_P(entry) == IS_OBJECT) {
+ dom_object *obj = Z_DOMOBJ_P(entry);
+ if (obj->document && obj->document->ptr == doc) {
+ return obj;
+ }
+ } else if (Z_TYPE_P(entry) == IS_ARRAY) {
+ zval *inner;
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(entry), inner) {
+ dom_object *obj = dom_xpath_intern_from_entry(inner, doc);
+ if (obj) {
+ return obj;
+ }
+ } ZEND_HASH_FOREACH_END();
+ }
+ return NULL;
+}
+
static dom_object *dom_xpath_intern_for_doc(dom_xpath_object *xpath_obj, xmlDocPtr doc)
{
if (xpath_obj->dom.document && xpath_obj->dom.document->ptr == doc) {
@@ -42,8 +61,8 @@ static dom_object *dom_xpath_intern_for_doc(dom_xpath_object *xpath_obj, xmlDocP
if (node_list) {
zval *entry;
ZEND_HASH_PACKED_FOREACH_VAL(node_list, entry) {
- dom_object *obj = Z_DOMOBJ_P(entry);
- if (obj->document && obj->document->ptr == doc) {
+ dom_object *obj = dom_xpath_intern_from_entry(entry, doc);
+ if (obj) {
return obj;
}
} ZEND_HASH_FOREACH_END();