Bug #62452 [Com]: Variable Aliasing does not work in Closure
| From: | john dot papaioannou at gmail dot com | Date: | Tue, 22 Oct 2013 10:33:31 +0000 |
| Subject: | Bug #62452 [Com]: Variable Aliasing does not work in Closure | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-182379@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=62452&edit=1
ID: 62452
Comment by: john dot papaioannou at gmail dot com
Reported by: hanskrentel at yahoo dot de
Summary: Variable Aliasing does not work in Closure
Status: Re-Opened
Type: Bug
Package: Scripting Engine problem
Operating System: Multiple
PHP Version: Irrelevant
Block user comment: N
Private report: N
New Comment:
This bug is really annoying. Here's another scenario that I just hit while refactoring:
set_exception_handler(function($exception) {
restore_exception_handler(); // boom
echo "Exception handled, move along.\n";
});
throw new Exception; // fatal error: cannot destroy active lambda
Previous Comments:
------------------------------------------------------------------------
[2012-09-15 15:42:10] nikic@php.net
I just looked into this a bit but couldn't find a good way to fix it. The main issue is that
the prototype hack is only done in ZEND_INIT_FCALL_BY_NAME and only for VARs. Doing the same for CVs
(as in this case) would be easy, but it sadly does not work properly if the closure is also invoked
using call_user_func or any other function using zend_call_function internally. zend_call_function
does not back the closure into the prototype and due to the way it works I'm not sure how this
could be added there. For zcf the get_closure object handler call is done within zend_is_callable_ex
and the results are put into the passed function_call_cache then. But the fcc can be reused for
multiple calls (or not be used at all), so I really don't know how to do this safely without
causing leaks or double frees.
------------------------------------------------------------------------
[2012-07-03 17:49:27] nikic@php.net
@laruence: The closure can still exist even if it is not referenced by $f anymore. I didn't
look into this yet, but the fix should be along the lines of adding a ref to the closure when it is
called and removing it again when it finishes running. Actually, I remember seeing something in the
code that backs up the function zval into op_array.prototype (disguised as a zend_function*) and
dtors it in the leave_helper. But clearly that isn't enough yet.
------------------------------------------------------------------------
[2012-07-03 17:39:24] hanskrentel at yahoo dot de
hi @laurence, thank's for taking the time to review it. If I write code like
unset($this);
it does not fatal error either (you can not destroy a object while you are calling
it.).
Also I don't want to destroy the closure, I just want to re-use that variable.
Can't you just let the garbage collector do the dirty work?
------------------------------------------------------------------------
[2012-07-02 07:03:19] laruence@php.net
you can not destroy a closure while you are calling it.
when you override $f in $f, zend vm try to destroy the closure $f, since the
refcout of it is 1.
try following :
$b = $f = function() use (&$f) {
$f = function() {};
};
$f();
$f();
------------------------------------------------------------------------
[2012-06-29 20:05:06] nikic@php.net
Verified on master.
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=62452
--
Edit this bug report at https://bugs.php.net/bug.php?id=62452&edit=1