[php-src] master: Zend: is_callable() wrongly accepts objects with no get_closure handler.

From: Date: Sat, 08 Aug 2026 17:50:36 +0000
Subject: [php-src] master: Zend: is_callable() wrongly accepts objects with no get_closure handler.
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-140547@lists.php.net to get a copy of this message
Author: David Carlier (devnexen) Date: 2026-08-08T18:50:19+01:00 Commit: https://github.com/php/php-src/commit/bb0ab98b9d2f415caa35398099cecff8f3247ac3 Raw diff: https://github.com/php/php-src/commit/bb0ab98b9d2f415caa35398099cecff8f3247ac3.diff Zend: is_callable() wrongly accepts objects with no get_closure handler. Fix #23121 zend_is_callable_at_frame() tested get_closure && get_closure(...) == FAILURE, so a NULL handler short circuited past the error branch into the success path, leaving fcc->function_handler NULL. zend_fcc_addref() then asserted and call_user_func() dereferenced the null zend_function. Close GH-23123 Changed paths: A Zend/tests/gh23121.phpt M NEWS M Zend/zend_API.c Diff: diff --git a/NEWS b/NEWS index 8c84bee9f71f..447d052e21dc 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,8 @@ PHP NEWS possible. (NickSdot) . Fixed GH-23083 (SEGV build_trace_args in zend_exceptions.c with -d error_include_args=On). (David Carlier) + . Fixed GH-23121 (is_callable() wrongly accepts objects with no get_closure + handler). (David Carlier) - Curl: . Improved cURL option validation errors to include the option name. diff --git a/Zend/tests/gh23121.phpt b/Zend/tests/gh23121.phpt new file mode 100644 index 000000000000..158794ba04e3 --- /dev/null +++ b/Zend/tests/gh23121.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-23121 (Assertion failure in zend_fcc_addref() for an object whose class has no get_closure handler) +--EXTENSIONS-- +simplexml +--FILE-- +<?php +$sxe = new SimpleXMLElement('<root/>'); + +var_dump(is_callable($sxe)); + +try { + $sxe(); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + call_user_func($sxe); +} catch (TypeError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + libxml_set_external_entity_loader($sxe); +} catch (TypeError $e) { + echo $e->getMessage(), PHP_EOL; +} + +var_dump(libxml_get_external_entity_loader()); +?> +--EXPECT-- +bool(false) +Object of type SimpleXMLElement is not callable +call_user_func(): Argument #1 ($callback) must be a valid callback, no array or string given +libxml_set_external_entity_loader(): Argument #1 ($resolver_function) must be a valid callback or null, no array or string given +NULL diff --git a/Zend/zend_API.c b/Zend/zend_API.c index de3570c5e848..7d407f7e9053 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -4240,7 +4240,7 @@ ZEND_API bool zend_is_callable_at_frame( } case IS_OBJECT: - if (Z_OBJ_HANDLER_P(callable, get_closure) && Z_OBJ_HANDLER_P(callable, get_closure)(Z_OBJ_P(callable), &fcc->calling_scope, &fcc->function_handler, &fcc->object, 1) == FAILURE) { + if (!Z_OBJ_HANDLER_P(callable, get_closure) || Z_OBJ_HANDLER_P(callable, get_closure)(Z_OBJ_P(callable), &fcc->calling_scope, &fcc->function_handler, &fcc->object, 1) == FAILURE) { if (error) *error = estrdup("no array or string given"); return 0; }

« previous php.cvs (#140547) next »