Commit 6eb8d06b578 for php
commit 6eb8d06b578ea2893c91c341dd1476ec0347ad79
Author: David Carlier <devnexen@gmail.com>
Date: Fri Sep 25 05:27:52 2026 +0100
Fix GH-23897: php:function() assertion after failed registerPHPFunctions()
A registerPHPFunctions() call that threw on a non callable name had
already allocated the callback namespace, leaving it in
PHP_DOM_REG_FUNC_MODE_NONE. The next php:function() call dispatched into
it and tripped the MODE_SET assertion.
Close GH-23900
diff --git a/NEWS b/NEWS
index 1de00a09ded..113e79508db 100644
--- a/NEWS
+++ b/NEWS
@@ -29,6 +29,8 @@ PHP NEWS
(Ilia Alshanetsky)
. Fixed bug GH-23729 (DOMXPath::__construct() use-after-free during an
evaluation). (David Carlier)
+ . Fixed bug GH-23897 (php:function() assertion failure after a failed
+ registerPHPFunctions()). (David Carlier)
- FTP:
. Fixed bug GH-23619 (cryptic error on servers that don't support TLS
diff --git a/ext/dom/tests/gh23897.phpt b/ext/dom/tests/gh23897.phpt
new file mode 100644
index 00000000000..79c465ec194
--- /dev/null
+++ b/ext/dom/tests/gh23897.phpt
@@ -0,0 +1,25 @@
+--TEST--
+GH-23897 (Assertion failure in php_dom_xpath_callback_dispatch() after failed registerPhpFunctions())
+--EXTENSIONS--
+dom
+--FILE--
+<?php
+$dom = new DOMDocument();
+$dom->loadXML('<root/>');
+
+$xpath = new DOMXPath($dom);
+$xpath->registerNamespace('php', 'http://php.net/xpath');
+try {
+ $xpath->registerPhpFunctions('testPhpFunction');
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+try {
+ var_dump($xpath->evaluate('php:function("testPhpFunction")'));
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+?>
+--EXPECT--
+TypeError: DOMXPath::registerPhpFunctions(): Argument #1 ($restrict) must be a callable, function "testPhpFunction" not found or invalid function name
+Error: No callbacks were registered
diff --git a/ext/dom/xpath_callbacks.c b/ext/dom/xpath_callbacks.c
index 5dd3c5caded..553671dbfa0 100644
--- a/ext/dom/xpath_callbacks.c
+++ b/ext/dom/xpath_callbacks.c
@@ -407,7 +407,7 @@ static zend_result php_dom_xpath_callback_dispatch(php_dom_xpath_callbacks *xpat
{
zval callback_retval;
- if (UNEXPECTED(ns == NULL)) {
+ if (UNEXPECTED(ns == NULL || ns->mode == PHP_DOM_REG_FUNC_MODE_NONE)) {
zend_throw_error(NULL, "No callbacks were registered");
return FAILURE;
}
diff --git a/ext/xsl/tests/gh23897.phpt b/ext/xsl/tests/gh23897.phpt
new file mode 100644
index 00000000000..cde0113153f
--- /dev/null
+++ b/ext/xsl/tests/gh23897.phpt
@@ -0,0 +1,36 @@
+--TEST--
+GH-23897 (Assertion failure in php_dom_xpath_callback_dispatch() after failed registerPHPFunctions())
+--EXTENSIONS--
+xsl
+--CREDITS--
+YuanchengJiang
+--FILE--
+<?php
+$dom = new DOMDocument();
+$dom->loadXML('<root><level1/></root>');
+
+$xsl = new DOMDocument();
+$xsl->loadXML(<<<XML
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl">
+<xsl:template match="root">
+<xsl:value-of select="php:function('testPhpFunction', .)" />
+</xsl:template>
+</xsl:stylesheet>
+XML);
+
+$xslt = new XSLTProcessor();
+try {
+ $xslt->registerPHPFunctions('testPhpFunction');
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+$xslt->importStylesheet($xsl);
+try {
+ var_dump($xslt->transformToXml($dom));
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+?>
+--EXPECT--
+TypeError: XSLTProcessor::registerPHPFunctions(): Argument #1 ($functions) must be a callable, function "testPhpFunction" not found or invalid function name
+Error: No callbacks were registered