diff --git a/ext/dom/tests/php_function_edge_cases.phpt b/ext/dom/tests/php_function_edge_cases.phpt
new file mode 100644
index 0000000000000..1091b50ce19bd
--- /dev/null
+++ b/ext/dom/tests/php_function_edge_cases.phpt
@@ -0,0 +1,27 @@
+--TEST--
+php:function() edge cases
+--EXTENSIONS--
+dom
+--FILE--
+loadHTML('hello');
+$xpath = new DOMXpath($doc);
+$xpath->registerNamespace("php", "http://php.net/xpath");
+$xpath->registerPHPFunctions();
+try {
+ $xpath->query("//a[php:function(3)]");
+} catch (TypeError $e) {
+ echo $e->getMessage(), "\n";
+}
+try {
+ $xpath->query("//a[php:function()]");
+} catch (Throwable $e) {
+ echo $e->getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+Handler name must be a string
+Function name must be passed as the first argument
diff --git a/ext/dom/xpath.c b/ext/dom/xpath.c
index 62e11f6b99bfb..af85e898ba44c 100644
--- a/ext/dom/xpath.c
+++ b/ext/dom/xpath.c
@@ -70,6 +70,11 @@ static void dom_xpath_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs,
return;
}
+ if (UNEXPECTED(nargs == 0)) {
+ zend_throw_error(NULL, "Function name must be passed as the first argument");
+ return;
+ }
+
fci.param_count = nargs - 1;
if (fci.param_count > 0) {
fci.params = safe_emalloc(fci.param_count, sizeof(zval), 0);
@@ -132,7 +137,7 @@ static void dom_xpath_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs,
if (obj->stringval == NULL) {
zend_type_error("Handler name must be a string");
xmlXPathFreeObject(obj);
- goto cleanup;
+ goto cleanup_no_callable;
}
ZVAL_STRING(&fci.function_name, (char *) obj->stringval);
xmlXPathFreeObject(obj);
@@ -177,6 +182,7 @@ static void dom_xpath_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs,
cleanup:
zend_string_release_ex(callable, 0);
zval_ptr_dtor_nogc(&fci.function_name);
+cleanup_no_callable:
if (fci.param_count > 0) {
for (i = 0; i < nargs - 1; i++) {
zval_ptr_dtor(&fci.params[i]);
diff --git a/ext/xsl/tests/php_function_edge_cases.phpt b/ext/xsl/tests/php_function_edge_cases.phpt
new file mode 100644
index 0000000000000..23a06b111bb50
--- /dev/null
+++ b/ext/xsl/tests/php_function_edge_cases.phpt
@@ -0,0 +1,45 @@
+--TEST--
+php:function() edge cases
+--EXTENSIONS--
+xsl
+--FILE--
+loadXML('
+
+
+
+
+ ');
+
+ $inputdom = new DomDocument();
+ $inputdom->loadXML('
+ ');
+
+ $proc = new XsltProcessor();
+ $proc->registerPhpFunctions();
+ $xsl = $proc->importStylesheet($xsl);
+ try {
+ $proc->transformToDoc($inputdom);
+ } catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+ }
+}
+
+try {
+ test("");
+} catch (Throwable $e) {
+ echo $e->getMessage(), "\n";
+}
+
+test("3");
+
+?>
+--EXPECTF--
+Function name must be passed as the first argument
+
+Warning: XSLTProcessor::transformToDoc(): Handler name must be a string in %s on line %d
diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c
index 0ddef864f050f..5de4b809ff9a5 100644
--- a/ext/xsl/xsltprocessor.c
+++ b/ext/xsl/xsltprocessor.c
@@ -141,6 +141,11 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t
return;
}
+ if (UNEXPECTED(nargs == 0)) {
+ zend_throw_error(NULL, "Function name must be passed as the first argument");
+ return;
+ }
+
fci.param_count = nargs - 1;
if (fci.param_count > 0) {
args = safe_emalloc(fci.param_count, sizeof(zval), 0);