php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #65775 Random memory leak between runs with identical data inputs
Submitted: 2013-09-27 18:35 UTC Modified: 2013-10-15 11:54 UTC
From: clyde dot adams at mailismagic dot com Assigned:
Status: No Feedback Package: *General Issues
PHP Version: Irrelevant OS: OSX Server 10.5.8
Private report: No CVE-ID:
Have you experienced this issue?
Rate the importance of this bug to you:

 [2013-09-27 18:35 UTC] clyde dot adams at mailismagic dot com
Description:
------------
While we are running PHP 5.3.27 here, I see nothing in the changelog for newer versions of PHP that indicates this bug is even possibly fixed.  The code on pastebin is a simplification of the scenario.  In my real-world environment, a query on a database is run, results are built up in an array in PHP, and then boiled down into a second array.  Everything is fine until the inner foreach() loop.  At that point, all bets are off as to whether or not PHP will run itself out of memory.  The exact same inputs resulting in the exact same data in $rows2 will sometimes cause PHP to suddenly chew up 128MB RAM and terminate the script - interestingly, not passing 'true' to memory_get_usage() says only 40MB is being used at the time PHP terminates the script while claiming 128MB RAM is being used.  The problem seems to hinge on this line:

$row[1] = htmlspecialchars(implode(", ", $idmap[$row[1]]));

If I break it out so the variable being assigned doesn't reference itself in the same statement:

$id = $idmap[$row[1]];
$row[1] = htmlspecialchars(implode(", ", $id));

The problem goes away as well.  There is nothing involved in the foreach statements beyond basic PHP arrays, numbers, and strings (i.e. no objects).  The amount of memory used before the foreach() lines is normal (about 10MB).  When the foreach statements complete successfully, the amount of memory used is still normal (about 20MB).  So there isn't always a runaway memory leak.

Attempting to replicate this issue will likely cause headaches.  When I added the commented out if-statement so I could output debugging information without affecting other users, the problem went away...even though the if-statement technically does absolutely nothing.  This made pinpointing the problem a lot more difficult in userland PHP.

There is indeed a bug here.  I wouldn't be filing a bug report or writing a test script if I wasn't certain about the issue.

Test script:
---------------
http://pastebin.com/z1KBmJLN

Expected result:
----------------
Consistent memory usage between runs with identical data.  If statements that do nothing should not have an effect on memory usage.

Actual result:
--------------
PHP inexplicably consumes all memory up to the limit in the INI file.  But only sometimes.  For the exact same inputs and data.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-09-27 20:02 UTC] rasmus@php.net
-Status: Open +Status: Feedback
 [2013-09-27 20:02 UTC] rasmus@php.net
Well, since we no longer support PHP 5.3.x you could at least try to replicate 
in PHP 5.4/5.5 and let us know if you are still able to.

I did a quick test using your provided script and couldn't see any issue.

Also, since I suspect you are only able to see this when running under a web 
server and not from CLI, you should indicate how you are running PHP, whether 
enable_gc is on or off and whether and which opcode you are using. All of which 
could affect this.
 [2013-09-27 20:35 UTC] clyde dot adams at mailismagic dot com
According to phpinfo():  zend.enable_gc On

No opcode cache.

Apache/2.2.21 (Unix) PHP/5.3.27 mod_ssl/2.2.21 OpenSSL/1.0.0h

Apache is running PHP as a module.

Unfortunately, I can't upgrade the box to 5.4 (yet).  Also, the test script I made doesn't replicate the problem for me either - it merely represents a working, pared back example of the data as it is headed into the foreach logic.
 [2013-10-03 20:39 UTC] clyde dot adams at mailismagic dot com
Update:  Built 5.5.4, ran 'make test', waited forever, and then it spit out 22 errors.  So, can't deploy 5.5.4.  Filed the report with PHP QA as requested by 'make test'.

=====================================================================
FAILED TEST SUMMARY
---------------------------------------------------------------------
Test DOMDocument::loadXML() detects not-well formed XML [ext/dom/tests/DOMDocument_loadXML_error4.phpt]
Test DOMDocument::load() detects not-well formed XML [ext/dom/tests/DOMDocument_load_error4.phpt]
DomDocument::schemaValidateSource() - string that is not a schema [ext/dom/tests/DOMDocument_schemaValidateSource_error1.phpt]
DomDocument::schemaValidateSource() - non-conforming schema [ext/dom/tests/DOMDocument_schemaValidateSource_error2.phpt]
DomDocument::schemaValidate() - file that is not a schema [ext/dom/tests/DOMDocument_schemaValidate_error1.phpt]
DomDocument::schemaValidate() - non-conforming schema file [ext/dom/tests/DOMDocument_schemaValidate_error2.phpt]
DomDocument::schemaValidate() - non-existent schema file [ext/dom/tests/DOMDocument_schemaValidate_error5.phpt]
Bug #42082 (NodeList length zero should be empty) [ext/dom/tests/bug42082.phpt]
Bug #47848 (importNode doesn't preserve attribute namespaces) [ext/dom/tests/bug47848.phpt]
Test 5: HTML Test [ext/dom/tests/dom005.phpt]
Test function getservbyname() [ext/standard/tests/general_functions/getservbyname_basic.phpt]
Test ceil() - basic function test for ceil() [ext/standard/tests/math/ceil_basic.phpt]
Test ip2long() function : usage variation 2, 32 bit [ext/standard/tests/network/ip2long_variation2.phpt]
xmlwriter_write_attribute_ns basic function tests [ext/xmlwriter/tests/xmlwriter_write_attribute_ns_basic_001.phpt]
xmlwriter_write_attribute_ns with missing param [ext/xmlwriter/tests/xmlwriter_write_attribute_ns_error_001.phpt]
xmlwriter_write_dtd basic function tests [ext/xmlwriter/tests/xmlwriter_write_dtd_basic_001.phpt]
Bug #52944 (segfault with zlib filter and corrupted data) [ext/zlib/tests/bug_52944-darwin.phpt]
Bug #65066 (Cli server not responsive when responding with 422 http status code): 100 status code [sapi/cli/tests/bug65066_100.phpt]
Bug #65066 (Cli server not responsive when responding with 422 http status code): 422 status code [sapi/cli/tests/bug65066_422.phpt]
Bug #65066 (Cli server not responsive when responding with 422 http status code): 511 status code [sapi/cli/tests/bug65066_511.phpt]
basic function [sapi/cli/tests/php_cli_server_001.phpt]
No router, no script [sapi/cli/tests/php_cli_server_013.phpt]
=====================================================================
 [2013-10-15 11:54 UTC] php-bugs at lists dot php dot net
No feedback was provided. The bug is being suspended because
we assume that you are no longer experiencing the problem.
If this is not the case and you are able to provide the
information that was requested earlier, please do so and
change the status of the bug back to "Re-Opened". Thank you.
 [2013-10-21 18:15 UTC] clyde dot adams at mailismagic dot com
Finally fixed the issue today.  I ended up rewriting most of the code but the problem still reared its head under specific conditions.  It finally went away when I called:

unserialize(serialize($row2));

Serializing and the unserializing forces a complete disconnect in the Zend allocator, which is exactly what should have happened in the first place.  The bug seems to only show up when htmlspecialchars() is called on a string and the output is assigned to an array.  In my case, each row only takes about 1KB RAM and there are only about 3,000 rows (approximately 3MB RAM should be used, not 128MB+), so the runaway memory issue technically still exists, but it has been buried in my particular case.
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Thu Apr 17 18:02:13 2014 UTC