Bug #64291 [Com]: Indeterminate GC of evaled lambda function resources
| From: | ulrich dot eckhardt at base-42 dot de | Date: | Mon, 17 Mar 2014 18:58:20 +0000 |
| Subject: | Bug #64291 [Com]: Indeterminate GC of evaled lambda function resources | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-184815@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=64291&edit=1
ID: 64291
Comment by: ulrich dot eckhardt at base-42 dot de
Reported by: Terry at ellisons dot org dot uk
Summary: Indeterminate GC of evaled lambda function resources
Status: Open
Type: Bug
Package: Scripting Engine problem
Operating System: Ubuntu 12.10
PHP Version: 5.4.12
Block user comment: N
Private report: N
New Comment:
I'm getting bitten by this bug, too. My use case is basically that I'm generating and
eval()'ing code. Since this is not in a one-shot HTTP server process environment but in a
longer running process that caches the generated code for performance reasons, this causes various
failures that depend on the order in which requests are made.
Using Terry's patch on PHP 5.4.24 on Debian/AMD64 caused the problem to go away, my services
now run stable. What's keeping you from applying this patch (apart from the fact that it mixes
tabs/spaces)?
Previous Comments:
------------------------------------------------------------------------
[2013-12-05 16:15:36] Terry at ellisons dot org dot uk
Dmitry,
I have just realised that this "mangled names should be unique" issue applied to any
runtime bound function or class as the following -- albeit perverse example shows:
--TEST--
ISSUE #65915A Temporary class entries are not unique
--INI--
opcache.enable=0
--SKIPIF--
--FILE--
<?php
$tmp = tempnam(__DIR__, 'test');
foreach (['a','b'] as $f) {
file_put_contents($tmp, <<<END
<?php
function $f() {
class Hello { const WORLD = "Hello world from $f\\n"; }
}
END
);
require $tmp;
}
a();
echo Hello::WORLD;
unlink($tmp);
?>
--CLEAN--
--EXPECT--
Hello world from a
Here the two functions both compile a class with a mangled name
"\0$class$filename$string_addr" which is the same for the a() and b() copies
so b() version overwrites the a() one, and the DECLARE_CLASS opcode in a() incorrecly binds to the
wrong class, hence Hello::WORLD incorrectly prints out the "from b" version.
However, I suspect in practice that this is unlikely to manifest itself in real word apps.
------------------------------------------------------------------------
[2013-11-25 13:26:28] Terry at ellisons dot org dot uk
Sorry, the above should read opcache.enable=0 though the failure is the same for opcache enabled and
not enabled in the eval case.
------------------------------------------------------------------------
[2013-11-25 13:24:08] Terry at ellisons dot org dot uk
And here's the eval version:
--TEST--
ISSUE #64291 Temporary function entries for closures are not unique
--INI--
opcache.enable=1
--FILE--
<?php
foreach (['a','b'] as $f) {
$tmp = "function $f() {return function(){ return '$f'; };}\n";
eval($tmp);
echo $tmp;
}
$a = a();
$b = b();
printf( "%s, %s\n ", $a(), $b());
?>
--EXPECT--
function a() {return function(){ return 'a'; };}
function b() {return function(){ return 'b'; };}
a, b
------------------------------------------------------------------------
[2013-11-25 12:42:16] Terry at ellisons dot org dot uk
What threw me was the botch with the temporary entries "\0{closure}$filenane$offset" are
used in the EG(function_table). This is as clear as mud. When a file is compiled, a function table
entry is created for each closue in the source. This entry is never executed directly, but is used
by the ZEND_DECLARE_LAMBDA_FUNCTION to construct the closure object which contains a deep copy of
this zend_function record. It is this copy that used when the closure is called. So long as the
ZEND_DECLARE_LAMBDA_FUNCTION
are executed within the same scope as the compile, this should normally be unique, but it is quite
easy to construct a test case which the unique assumption fails:
--TEST--
ISSUE #65915 Temporary function entries for closures are not unique
--INI--
opcache.enable=0
--SKIPIF--
--FILE--
<?php
$tmp = tempnam(__DIR__, 'test');
foreach (['a','b'] as $f) {
file_put_contents($tmp, "<?php function $f() {return function(){ return '$f';
};}");
echo file_get_contents($tmp), "\n";
require $tmp;
}
$a = a();
$b = b();
printf( "%s, %s\n ", $a(), $b());
unlink($tmp);
?>
--CLEAN--
--EXPECT--
<?php function a() {return function(){ return 'a'; };}
<?php function b() {return function(){ return 'b'; };}
a, b
------------------------------------------------------------------------
[2013-11-25 08:53:35] dmitry@php.net
Your second script prints "a, a" only with OPCache, because it caches the included
temporary file. Without OPCache it prints the expected "a, b".
I also don't think that the first script indicates a bug. The more functions you create the
more memory it requires.
------------------------------------------------------------------------
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=64291
--
Edit this bug report at https://bugs.php.net/bug.php?id=64291&edit=1