Edit report at https://bugs.php.net/bug.php?id=61792&edit=1
ID: 61792
Comment by: andrew at mcnaughty dot com
Reported by: tshaw at oitc dot com
Summary: preg_replace_callback memory leak
Status: Not a bug
Type: Bug
Package: PCRE related
Operating System: OSX 10.7.3
PHP Version: 5.4.0
Block user comment: N
Private report: N
New Comment:
Actually I think this bug or something very like it still exists with an
anonymous function:
I'm seeing a leak with the following code:
------
$this->contact['email_greeting_display'] = preg_replace_callback(
'@\{(?:contact\.)?([a-z0-9._]*)\}@',
function($matches) use ($prefixes,$contact) {
if ($matches[1] == 'individual_prefix') {
return $prefixes[$contact['prefix_id']];
}
else {
return $contact[$matches[1]];
}
},
$format['greeting']
------
Previous Comments:
------------------------------------------------------------------------
[2012-04-21 01:46:59] anon at anon dot anon
@tshaw: The problem is that create_function is a nasty old construct that adds
a new function every time you call it, even if the code to compile is the same
each time. The created functions are *permanent* and create_function returns
their name only -- so even if the variable containing their name goes out of
scope, the created functions persist. Naturally, 10 million functions take a
lot of memory. It's not technically a bug, just awful language design.
You can create the functions once statically and store their names, or since
PHP 5.3.0, you can use anonymous functions instead. Try this:
function urlDecodeUnreservedChars( $string ) {
$unreserved = array();
$unreserved[] = dechex( ord( '-' ) );
$unreserved[] = dechex( ord( '.' ) );
$unreserved[] = dechex( ord( '_' ) );
$unreserved[] = dechex( ord( '~' ) );
return preg_replace_callback(
array_map(function ($str) { return '/%' . strtoupper($str) .
'/x'; }, $unreserved),
function ($matches) { return chr(hexdec($matches[0])); },
$string
);
}
------------------------------------------------------------------------
[2012-04-20 22:45:09] tshaw at oitc dot com
I am totally confused.
You say that its OK for PHP to fail with a memory exhausted error when running
a
perfectly valid CLI script that happens to fail on the 180951 iteration? I say
this is absolutely bug!
There may be no memory leak but it surely is a bug as a CLI script that
iterates
a long period of time is not out of line.
I respectfully request you reconsider and change this back to a bug.
------------------------------------------------------------------------
[2012-04-20 22:24:28] [email protected]
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php
There is no memory leak, what happens is that the memory associated to the
lambda functions (via create_function()) is just released in the end of
execution.
------------------------------------------------------------------------
[2012-04-20 21:40:54] tshaw at oitc dot com
Description:
------------
$ ./ptest.php
Test preg_replace_callback
Iteration number 0
Iteration number 1
....
Iteration number 180951
PHP Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to
allocate 3072 bytes) in /Users/tshaw/Sites/surbl/ptest.php(11) :
runtime-created
function on line 1
Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to
allocate
3072 bytes) in /Users/tshaw/Sites/surbl/ptest.php(11) : runtime-created
function
on line 1
Test script:
---------------
#!/usr/local/php5/bin/php
<?PHP
// #!/usr/bin/php
error_reporting(E_ALL);
function urlDecodeUnreservedChars( $string ) {
$unreserved = array();
$unreserved[] = dechex( ord( '-' ) );
$unreserved[] = dechex( ord( '.' ) );
$unreserved[] = dechex( ord( '_' ) );
$unreserved[] = dechex( ord( '~' ) );
return preg_replace_callback( array_map( create_function( '$str',
'return "/%" . strtoupper( $str ) . "/x";' ), $unreserved ), create_function(
'$matches', 'return chr( hexdec( $matches[0] ));' ), $string );
}
for ($i=0; $i <5000000; $i++) {
echo "Iteration number $i\n";
urlDecodeUnreservedChars( "12345" );
}
?>
Expected result:
----------------
Expected it to run to completion
Actual result:
--------------
PHP Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to
allocate 3072 bytes) in /Users/tshaw/Sites/surbl/ptest.php(11) :
runtime-created
function on line 1
Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to
allocate
3072 bytes) in /Users/tshaw/Sites/surbl/ptest.php(11) : runtime-created
function
on line 1
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=61792&edit=1