From a2cdb89100afdb95f25473082c785f2cdbeff9e3 Mon Sep 17 00:00:00 2001 From: lazerg Date: Wed, 30 Sep 2026 05:23:06 +0100 Subject: [PATCH] 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 --- NEWS | 2 ++ Zend/tests/gh23896.phpt | 33 ++++++++++++++++++++++++++++ Zend/zend_execute_API.c | 6 +++++ ext/xsl/tests/throw_in_autoload.phpt | 4 +--- 4 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 Zend/tests/gh23896.phpt diff --git a/NEWS b/NEWS index 40236c24a008..2f56de0d1b2e 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 000000000000..1524bdb55161 --- /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-- +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 9ccb36a1e15a..95ff2e4f42fa 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 2df7d3690bed..90ab0098b8e4 100644 --- a/ext/xsl/tests/throw_in_autoload.phpt +++ b/ext/xsl/tests/throw_in_autoload.phpt @@ -28,14 +28,12 @@ $proc->registerPhpFunctions(); $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===