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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: nicolas dot grekas+php at gmail dot com
New email:
PHP Version: OS:

 

 [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: Sat Nov 23 08:01:28 2024 UTC