php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78689 Closure::fromCallable() doesn't handle [Closure, '__invoke']
Submitted: 2019-10-18 12:06 UTC Modified: 2019-10-28 11:31 UTC
From: nicolas dot grekas+php at gmail dot com Assigned:
Status: Closed Package: Scripting Engine problem
PHP Version: 7.3.10 OS:
Private report: No CVE-ID: None
 [2019-10-18 12:06 UTC] nicolas dot grekas+php at gmail dot com
Description:
------------
php > $a = [function () { echo 123; }, '__invoke'];
php > $a();
123
php > $b = Closure::fromCallable($a);
php > $b();
PHP Warning:  Invalid callback , no array or string given in php shell code on line 1
PHP Stack trace:
PHP   1. {main}() php shell code:0
PHP   2. Closure->__invoke() php shell code:1
php > 

The warning is wrong - Closure::fromCallable() could return $a actually :)


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-10-28 11:13 UTC] nikic@php.net
-Status: Open +Status: Verified
 [2019-10-28 11:13 UTC] nikic@php.net
This actually gives me a segfault on 7.2:

==24448== Jump to the invalid address stated on the next line
==24448==    at 0x600000001: ???
==24448==    by 0x9FE0E9: zend_call_function (zend_execute_API.c:820)
==24448==    by 0xA52718: zend_closure_call_magic (zend_closures.c:252)
==24448==    by 0xA538BB: zend_closure_internal_handler (zend_closures.c:632)
==24448==    by 0xA7E0C8: ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:911)
==24448==    by 0xB03C47: execute_ex (zend_vm_execute.h:59781)
==24448==    by 0xB09005: zend_execute (zend_vm_execute.h:63792)
==24448==    by 0xA186A1: zend_execute_scripts (zend.c:1498)
==24448==    by 0x97BDB3: php_execute_script (main.c:2599)
==24448==    by 0xB0BCAD: do_cli (php_cli.c:1011)
==24448==    by 0xB0CE6B: main (php_cli.c:1403)
==24448==  Address 0x600000001 is not stack'd, malloc'd or (recently) free'd
 [2019-10-28 11:22 UTC] nikic@php.net
-Status: Verified +Status: Analyzed
 [2019-10-28 11:22 UTC] nikic@php.net
It looks like there's a hardcoded assumption that any trampoline function passed to Closure::fromCallable() must be a __call/__callStatic trampoline, while here it's an __invoke() call-via-handler.
 [2019-10-28 11:31 UTC] nicolas dot grekas+php at gmail dot com
Note that we could take this as an opportunity to introduce a new type of callables:

given [$closure, 'method'], this would be resolved as $closure()->method() when called.

We use this style in Symfony where we need lazy-callables.
 [2019-10-29 14:09 UTC] nikic@php.net
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=f9895b4bf5c6cdef0106f763cd95d95e98f039ae
Log: Fixed bug #78689
 [2019-10-29 14:09 UTC] nikic@php.net
-Status: Analyzed +Status: Closed
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Oct 14 05:01:28 2024 UTC