From e6124aececf88bb3d115acf943db32339b387cd2 Mon Sep 17 00:00:00 2001 From: lazerg Date: Fri, 25 Sep 2026 13:35:27 +0500 Subject: [PATCH 1/4] Fix GH-23896: Assertion failure in zend_call_function() after a throwing deprecation --- NEWS | 3 +++ Zend/tests/gh23896.phpt | 25 +++++++++++++++++++++++++ Zend/zend_execute_API.c | 5 ++++- 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/gh23896.phpt diff --git a/NEWS b/NEWS index 1de00a09ded0..9434f6a4cdbe 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,9 @@ PHP NEWS comparison. (Arnaud) . Fixed OSS-Fuzz #536440507 (Immutable class incorrect assertion). (ndossche) + . Fixed bug GH-23896 (Assertion failure in zend_call_function() when the + error handler throws while resolving a self::/parent::/static:: + callable). (Lazizbek Ergashev) - 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..caa7c6ca507c --- /dev/null +++ b/Zend/tests/gh23896.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-23896 (Assertion failure in zend_call_function() when the error handler throws during parent:: callable resolution) +--INI-- +unserialize_callback_func=parent::my_unserialize +--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 diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 9ccb36a1e15a..5f161a63b89f 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -824,7 +824,10 @@ 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)) { - ZEND_ASSERT(error && "Should have error if not callable"); + if (!error) { + ZEND_ASSERT(EG(exception) && "Should have error if not callable"); + return SUCCESS; + } zend_string *callable_name = zend_get_callable_name_ex(&fci->function_name, fci->object); zend_throw_error(NULL, "Invalid callback %s, %s", ZSTR_VAL(callable_name), error); From 746ace73cad0d2a071227da0f464360d8ec8b121 Mon Sep 17 00:00:00 2001 From: lazerg Date: Fri, 25 Sep 2026 13:48:32 +0500 Subject: [PATCH 2/4] Drop the stale message from the zend_call_function() exception assert --- Zend/zend_execute_API.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 5f161a63b89f..3284e02dde23 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -825,7 +825,7 @@ 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 (!error) { - ZEND_ASSERT(EG(exception) && "Should have error if not callable"); + ZEND_ASSERT(EG(exception)); return SUCCESS; } zend_string *callable_name From 9691d2ca9b53b791373376248d6667b6a65b8b1b Mon Sep 17 00:00:00 2001 From: lazerg Date: Fri, 25 Sep 2026 16:10:07 +0500 Subject: [PATCH 3/4] Return early on a pending exception before the zend_call_function() assert --- Zend/tests/gh23896.phpt | 22 +++++++++++++++------- Zend/zend_execute_API.c | 7 +++++-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/Zend/tests/gh23896.phpt b/Zend/tests/gh23896.phpt index caa7c6ca507c..1524bdb55161 100644 --- a/Zend/tests/gh23896.phpt +++ b/Zend/tests/gh23896.phpt @@ -1,25 +1,33 @@ --TEST-- GH-23896 (Assertion failure in zend_call_function() when the error handler throws during parent:: callable resolution) ---INI-- -unserialize_callback_func=parent::my_unserialize --FILE-- u('O:3:"FOO":0:{}'); -} catch (Exception $e) { - echo $e->getMessage(), "\n"; - var_dump($e->getPrevious()); +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 3284e02dde23..95ff2e4f42fa 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -824,10 +824,13 @@ 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 (!error) { - ZEND_ASSERT(EG(exception)); + 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); zend_throw_error(NULL, "Invalid callback %s, %s", ZSTR_VAL(callable_name), error); From 9993cf02315a229a50231442e344c1226612e11c Mon Sep 17 00:00:00 2001 From: lazerg Date: Wed, 30 Sep 2026 07:43:24 +0500 Subject: [PATCH 4/4] Update ext/xsl throw_in_autoload.phpt for the unchained autoload exception --- ext/xsl/tests/throw_in_autoload.phpt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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===