Commit a2cdb89100a for php

commit a2cdb89100afdb95f25473082c785f2cdbeff9e3
Author: lazerg <lazerg2@gmail.com>
Date:   Wed Sep 30 05:23:06 2026 +0100

    Fix GH-23896: Assertion failure in zend_call_function() after a throwing deprecation

    Since GH-21699, zend_is_callable_check_class() returns false without
    setting error when the error handler throws on the self/parent/static
    deprecation. zend_call_function() asserted that a failed callable check
    always comes with an error message, so calling such a string callback
    through call_user_function() (here unserialize_callback_func=parent::...)
    aborts on debug builds.

    When the check fails with no error, the exception from the handler is
    already pending, so zend_call_function() now returns early without
    throwing a second one, the same way it does when it is entered with an
    exception.

    Close GH-23903

diff --git a/NEWS b/NEWS
index 40236c24a00..2f56de0d1b2 100644
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,8 @@ PHP                                                                        NEWS
   . Fixed AVX being reported as supported when the OS has not enabled AVX
     state. (Ilia Alshanetsky)
   . Fixed GH-23980 (ZEND_ASSERT violation @ ZEND_INCLUDE_OR_EVAL). (ndossche)
+  . Fixed bug GH-23896 (Assertion failure in zend_call_function() after a
+    throwing deprecation). (lazerg)

 - DOM:
   . Fixed use-after-free when re-constructing a DOMXPath whose php:function
diff --git a/Zend/tests/gh23896.phpt b/Zend/tests/gh23896.phpt
new file mode 100644
index 00000000000..1524bdb5516
--- /dev/null
+++ b/Zend/tests/gh23896.phpt
@@ -0,0 +1,33 @@
+--TEST--
+GH-23896 (Assertion failure in zend_call_function() when the error handler throws during parent:: callable resolution)
+--FILE--
+<?php
+set_error_handler(function ($severity, $m) {
+    throw new Exception($m, $severity);
+});
+spl_autoload_register(function ($class) {
+    if ($class === 'Loader') {
+        throw new Exception("Cannot load $class");
+    }
+});
+class P {}
+class C extends P {
+    public function u(string $s) {
+        return unserialize($s);
+    }
+}
+foreach (['parent::my_unserialize', 'Loader::load'] as $callback) {
+    ini_set('unserialize_callback_func', $callback);
+    try {
+        (new C)->u('O:3:"FOO":0:{}');
+    } catch (Exception $e) {
+        echo $e->getMessage(), "\n";
+        var_dump($e->getPrevious());
+    }
+}
+?>
+--EXPECT--
+Use of "parent" in callables is deprecated
+NULL
+Cannot load Loader
+NULL
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index 9ccb36a1e15..95ff2e4f42f 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -824,6 +824,12 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_
 		}

 		if (!zend_is_callable_ex(&fci->function_name, fci->object, 0, NULL, fci_cache, &error)) {
+			if (EG(exception)) {
+				if (error) {
+					efree(error);
+				}
+				return SUCCESS;
+			}
 			ZEND_ASSERT(error && "Should have error if not callable");
 			zend_string *callable_name
 				= zend_get_callable_name_ex(&fci->function_name, fci->object);
diff --git a/ext/xsl/tests/throw_in_autoload.phpt b/ext/xsl/tests/throw_in_autoload.phpt
index 2df7d3690be..90ab0098b8e 100644
--- a/ext/xsl/tests/throw_in_autoload.phpt
+++ b/ext/xsl/tests/throw_in_autoload.phpt
@@ -28,14 +28,12 @@
 $xsl = $proc->importStylesheet($xsl);
 try {
     $newdom = $proc->transformToDoc($inputdom);
-} catch (Error $e) {
+} catch (Exception $e) {
     echo $e->getMessage(), "\n";
-    echo $e->getPrevious()->getMessage(), "\n";
 }
 ?>
 ===DONE===
 --EXPECT--
 string(4) "TeSt"
-Invalid callback TeSt::dateLang, class "TeSt" not found
 Autoload exception
 ===DONE===