[php-src] PHP-8.6: Merge branch 'PHP-8.5' into PHP-8.6

From: Date: Mon, 05 Oct 2026 11:28:25 +0000
Subject: [php-src] PHP-8.6: Merge branch 'PHP-8.5' into PHP-8.6
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-141956@lists.php.net to get a copy of this message
Author: Ilia Alshanetsky (iliaal) Date: 2026-10-05T07:14:22-04:00 Commit: https://github.com/php/php-src/commit/2290177565d8ded70f8b1c1677f24e1b2d6b5f24 Raw diff: https://github.com/php/php-src/commit/2290177565d8ded70f8b1c1677f24e1b2d6b5f24.diff Merge branch 'PHP-8.5' into PHP-8.6 * PHP-8.5: ext/dom: Restore the XPath context after a reentrant evaluation Changed paths: A ext/dom/tests/xpath_reentrant_context.phpt M NEWS M ext/dom/xpath.c Diff: diff --git a/NEWS b/NEWS index bc63b84709c2..30869309af87 100644 --- a/NEWS +++ b/NEWS @@ -39,6 +39,11 @@ PHP NEWS . Fixed System V shared memory emulation for Windows attaching segments past the end of their mapping. (Ilia Alshanetsky) +- DOM: + . Fixed DOMXPath and Dom\XPath losing the context node and in-scope + namespaces of an evaluation after a php:function() callback evaluated + another expression on the same object. (Ilia Alshanetsky) + - FFI: . Fixed crashes with FFI callbacks created from __call() trampolines and array callables whose object is released. (Ilia Alshanetsky) diff --git a/ext/dom/tests/xpath_reentrant_context.phpt b/ext/dom/tests/xpath_reentrant_context.phpt new file mode 100644 index 000000000000..4a307ae1dfc5 --- /dev/null +++ b/ext/dom/tests/xpath_reentrant_context.phpt @@ -0,0 +1,54 @@ +--TEST-- +DOMXPath: Reentrant evaluation must restore the context node and namespaces +--EXTENSIONS-- +dom +--FILE-- +<?php +$doc = new DOMDocument(); +$doc->loadXML('<r xmlns:p="urn:p"><a><x>A</x><p:y/></a><a><x>A2</x></a><b><x>B</x><x>B2</x><x>B3</x></b></r>'); +$xp = new DOMXPath($doc); +$xp->registerNamespace('php', 'http://php.net/xpath'); +$xp->registerPhpFunctions(); +$b = $doc->documentElement->lastElementChild; +$GLOBALS['xp'] = $xp; +$GLOBALS['b'] = $b; +function callback($node) { + $GLOBALS['xp']->query('x[2]', $GLOBALS['b']); + return true; +} + +echo "context node:\n"; +var_dump($xp->query('a[php:function("callback", .) and x]', $doc->documentElement)->length); +var_dump($xp->evaluate('count(a[php:function("callback", .) and x])', $doc->documentElement)); + +echo "in-scope namespace:\n"; +var_dump($xp->query('a[php:function("callback", .) and p:y]', $doc->documentElement)->length); + +echo "position and size:\n"; +var_dump($xp->query('a[php:function("callback", .) and position() = 2]', $doc->documentElement)->length); +var_dump($xp->query('a[php:function("callback", .) and last() = 2]', $doc->documentElement)->length); + +echo "after reentry:\n"; +var_dump($xp->query('a[x]', $doc->documentElement)->length); + +echo "Dom\\XPath:\n"; +$modern = Dom\XMLDocument::createFromString('<r><a><x>A</x></a><a><x>A2</x></a><b><x>B</x><x>B2</x><x>B3</x></b></r>'); +$GLOBALS['xp'] = new Dom\XPath($modern); +$GLOBALS['xp']->registerNamespace('php', 'http://php.net/xpath'); +$GLOBALS['xp']->registerPhpFunctions(); +$GLOBALS['b'] = $modern->documentElement->lastElementChild; +var_dump($GLOBALS['xp']->query('a[php:function("callback", .) and x]', $modern->documentElement)->length); +?> +--EXPECT-- +context node: +int(2) +float(2) +in-scope namespace: +int(1) +position and size: +int(1) +int(2) +after reentry: +int(2) +Dom\XPath: +int(2) diff --git a/ext/dom/xpath.c b/ext/dom/xpath.c index cff89553aa81..9f00363f25da 100644 --- a/ext/dom/xpath.c +++ b/ext/dom/xpath.c @@ -318,6 +318,10 @@ static void php_xpath_eval(INTERNAL_FUNCTION_PARAMETERS, int type, bool modern) RETURN_THROWS(); } + xmlNodePtr old_node = ctxp->node; + xmlNsPtr *old_namespaces = ctxp->namespaces; + int old_nsNr = ctxp->nsNr; + ctxp->node = nodep; php_dom_in_scope_ns in_scope_ns; @@ -335,12 +339,12 @@ static void php_xpath_eval(INTERNAL_FUNCTION_PARAMETERS, int type, bool modern) intern->evaluation_depth++; xmlXPathObjectPtr xpathobjp = xmlXPathEvalExpression(BAD_CAST expr, ctxp); intern->evaluation_depth--; - ctxp->node = NULL; + ctxp->node = old_node; + ctxp->namespaces = old_namespaces; + ctxp->nsNr = old_nsNr; if (register_node_ns && nodep != NULL) { php_dom_in_scope_ns_destroy(&in_scope_ns); - ctxp->namespaces = NULL; - ctxp->nsNr = 0; } if (! xpathobjp) {

« previous php.cvs (#141956) next »