Skip to content

Commit a2cdb89

Browse files
lazergdevnexen
authored andcommitted
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
1 parent c8d62b8 commit a2cdb89

4 files changed

Lines changed: 42 additions & 3 deletions

File tree

‎NEWS‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ PHP NEWS
2222
. Fixed AVX being reported as supported when the OS has not enabled AVX
2323
state. (Ilia Alshanetsky)
2424
. Fixed GH-23980 (ZEND_ASSERT violation @ ZEND_INCLUDE_OR_EVAL). (ndossche)
25+
. Fixed bug GH-23896 (Assertion failure in zend_call_function() after a
26+
throwing deprecation). (lazerg)
2527

2628
- DOM:
2729
. Fixed use-after-free when re-constructing a DOMXPath whose php:function

‎Zend/tests/gh23896.phpt‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
GH-23896 (Assertion failure in zend_call_function() when the error handler throws during parent:: callable resolution)
3+
--FILE--
4+
<?php
5+
set_error_handler(function ($severity, $m) {
6+
throw new Exception($m, $severity);
7+
});
8+
spl_autoload_register(function ($class) {
9+
if ($class === 'Loader') {
10+
throw new Exception("Cannot load $class");
11+
}
12+
});
13+
class P {}
14+
class C extends P {
15+
public function u(string $s) {
16+
return unserialize($s);
17+
}
18+
}
19+
foreach (['parent::my_unserialize', 'Loader::load'] as $callback) {
20+
ini_set('unserialize_callback_func', $callback);
21+
try {
22+
(new C)->u('O:3:"FOO":0:{}');
23+
} catch (Exception $e) {
24+
echo $e->getMessage(), "\n";
25+
var_dump($e->getPrevious());
26+
}
27+
}
28+
?>
29+
--EXPECT--
30+
Use of "parent" in callables is deprecated
31+
NULL
32+
Cannot load Loader
33+
NULL

‎Zend/zend_execute_API.c‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,12 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_
824824
}
825825

826826
if (!zend_is_callable_ex(&fci->function_name, fci->object, 0, NULL, fci_cache, &error)) {
827+
if (EG(exception)) {
828+
if (error) {
829+
efree(error);
830+
}
831+
return SUCCESS;
832+
}
827833
ZEND_ASSERT(error && "Should have error if not callable");
828834
zend_string *callable_name
829835
= zend_get_callable_name_ex(&fci->function_name, fci->object);

‎ext/xsl/tests/throw_in_autoload.phpt‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,12 @@ $proc->registerPhpFunctions();
2828
$xsl = $proc->importStylesheet($xsl);
2929
try {
3030
$newdom = $proc->transformToDoc($inputdom);
31-
} catch (Error $e) {
31+
} catch (Exception $e) {
3232
echo $e->getMessage(), "\n";
33-
echo $e->getPrevious()->getMessage(), "\n";
3433
}
3534
?>
3635
===DONE===
3736
--EXPECT--
3837
string(4) "TeSt"
39-
Invalid callback TeSt::dateLang, class "TeSt" not found
4038
Autoload exception
4139
===DONE===

0 commit comments

Comments
 (0)