: Bug #66091 :: Memory leak in DateTime::createFromFormat()

Bug #66091 Memory leak in DateTime::createFromFormat()
Submitted: 2013-11-13 17:01 UTC Modified: 2014-04-06 13:00 UTC
Votes:7
Avg. Score:4.4 ± 0.9
Reproduced:7 of 7 (100.0%)
Same Version:6 (85.7%)
Same OS:7 (100.0%)
From: lars_teuber at gmx dot de Assigned: ab (profile)
Status: Closed Package: Unknown/Other Function
PHP Version: Irrelevant OS: Windows/Linux
Private report: No CVE-ID: None

 [2013-11-13 17:01 UTC] lars_teuber at gmx dot de

Description:
------------
Hi,

DateTime::createFromFormat() has a memory leak.

Tested with: 5.3.14, 5.4.4, 5.5.3

Best regards
Lars Teuber

Test script:
---------------
<?php
$mem_start = memory_get_usage(true);
echo 'start: ' . $mem_start . '<br>';

$max_iterations = 1000000;
for ($i = 1; $i <= $max_iterations; $i++) {
    DateTime::createFromFormat('M/D/Y H:i:s', '2013-11-12 20:00:00');
    if (($i % 100000) == 0) {
        echo $i . '.: ' . memory_get_usage(true) . '<br>';
    }
}
$mem_end = memory_get_usage(true);
echo 'end: ' . $mem_end . '<br>';
echo 'diff end-start: ' . ($mem_end - $mem_start) . '<br>';
?>

Expected result:
----------------
(more or less) constant memory usage

Actual result:
--------------
start:             524288
100000.:         16777216
200000.:         33030144
300000.:         53477376
400000.:         65536000
500000.:         77594624
600000.:        106168320
700000.:        118226944
800000.:        130285568
900000.:        142344192
1000000.:       154140672
end:            154140672
diff end-start: 153616384

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports

 [2014-04-05 17:03 UTC] ab@php.net

But in your code, you just continuously create new objects. It is then logic that the memory is cluttered up. Try using the return value and then explicitly unset() it.

 [2014-04-05 17:03 UTC] ab@php.net

-Status: Open +Status: Not a bug -Assigned To: +Assigned To: ab

 [2014-04-05 19:53 UTC] nikic@php.net

@ab: If you don't use the return value of a function call, it will be immidiately destroyed. As such there should be no difference between ignoring the return value and doing an assing+unset. To me this looks like we're indeed leaking something.

 [2014-04-06 13:00 UTC] ab@php.net

-Status: Not a bug +Status: Assigned

 [2014-04-06 13:00 UTC] ab@php.net

@nikic, now looking at the code of date_load_from_format i think you're right. In case it has to RETURN_FALSE a leak is possible. I will check that, thanks.

 [2014-07-18 04:31 UTC] nurlan0000 at gmail dot com

@ab, It's been almost a year since the bug was reported. Any updates on this?

 [2014-07-18 05:07 UTC] nurlan0000 at gmail dot com

Here's the valgrind output for test.php:

for ( $i = 0; $i < 100000; $i++ ) {
    $d = DateTime::createFromFormat('m-d-Y', '05-21-2014');
    unset($d);
}

valgrind --leak-check=yes --leak-check=full --show-leak-kinds=all php test.php


==21278== 5,922 bytes in 416 blocks are still reachable in loss record 14 of 18
==21278==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21278==    by 0x698C679: strdup (strdup.c:42)
==21278==    by 0x48BCB4: ??? (in /usr/bin/php5)
==21278==    by 0x48C164: timelib_builtin_db (in /usr/bin/php5)
==21278==    by 0x46D1CC: php_date_initialize (in /usr/bin/php5)
==21278==    by 0x46D41D: zif_date_create_from_format (in /usr/bin/php5)
==21278==    by 0x6DD6BA: dtrace_execute_internal (in /usr/bin/php5)
==21278==    by 0x79D714: ??? (in /usr/bin/php5)
==21278==    by 0x717447: execute_ex (in /usr/bin/php5)
==21278==    by 0x6DD5B8: dtrace_execute_ex (in /usr/bin/php5)
==21278==    by 0x6EF03F: zend_execute_scripts (in /usr/bin/php5)
==21278==    by 0x68EF24: php_execute_script (in /usr/bin/php5)
==21278== 
==21278== 8,168 bytes in 1 blocks are still reachable in loss record 15 of 18
==21278==    at 0x4C2CC70: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21278==    by 0x48BB48: ??? (in /usr/bin/php5)
==21278==    by 0x48C164: timelib_builtin_db (in /usr/bin/php5)
==21278==    by 0x46D1CC: php_date_initialize (in /usr/bin/php5)
==21278==    by 0x46D41D: zif_date_create_from_format (in /usr/bin/php5)
==21278==    by 0x6DD6BA: dtrace_execute_internal (in /usr/bin/php5)
==21278==    by 0x79D714: ??? (in /usr/bin/php5)
==21278==    by 0x717447: execute_ex (in /usr/bin/php5)
==21278==    by 0x6DD5B8: dtrace_execute_ex (in /usr/bin/php5)
==21278==    by 0x6EF03F: zend_execute_scripts (in /usr/bin/php5)
==21278==    by 0x68EF24: php_execute_script (in /usr/bin/php5)
==21278==    by 0x79F6ED: ??? (in /usr/bin/php5)
==21278== 
==21278== 9,029 bytes in 594 blocks are still reachable in loss record 16 of 18
==21278==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21278==    by 0x698C679: strdup (strdup.c:42)
==21278==    by 0x48B994: ??? (in /usr/bin/php5)
==21278==    by 0x48C15F: timelib_builtin_db (in /usr/bin/php5)
==21278==    by 0x46D1CC: php_date_initialize (in /usr/bin/php5)
==21278==    by 0x46D41D: zif_date_create_from_format (in /usr/bin/php5)
==21278==    by 0x6DD6BA: dtrace_execute_internal (in /usr/bin/php5)
==21278==    by 0x79D714: ??? (in /usr/bin/php5)
==21278==    by 0x717447: execute_ex (in /usr/bin/php5)
==21278==    by 0x6DD5B8: dtrace_execute_ex (in /usr/bin/php5)
==21278==    by 0x6EF03F: zend_execute_scripts (in /usr/bin/php5)
==21278==    by 0x68EF24: php_execute_script (in /usr/bin/php5)
==21278== 
==21278== 16,384 bytes in 1 blocks are still reachable in loss record 17 of 18
==21278==    at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21278==    by 0x48BA89: ??? (in /usr/bin/php5)
==21278==    by 0x48C15F: timelib_builtin_db (in /usr/bin/php5)
==21278==    by 0x46D1CC: php_date_initialize (in /usr/bin/php5)
==21278==    by 0x46D41D: zif_date_create_from_format (in /usr/bin/php5)
==21278==    by 0x6DD6BA: dtrace_execute_internal (in /usr/bin/php5)
==21278==    by 0x79D714: ??? (in /usr/bin/php5)
==21278==    by 0x717447: execute_ex (in /usr/bin/php5)
==21278==    by 0x6DD5B8: dtrace_execute_ex (in /usr/bin/php5)
==21278==    by 0x6EF03F: zend_execute_scripts (in /usr/bin/php5)
==21278==    by 0x68EF24: php_execute_script (in /usr/bin/php5)
==21278==    by 0x79F6ED: ??? (in /usr/bin/php5)
==21278== 
==21278== 43,264 bytes in 416 blocks are still reachable in loss record 18 of 18
==21278==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21278==    by 0x48BC85: ??? (in /usr/bin/php5)
==21278==    by 0x48C164: timelib_builtin_db (in /usr/bin/php5)
==21278==    by 0x46D1CC: php_date_initialize (in /usr/bin/php5)
==21278==    by 0x46D41D: zif_date_create_from_format (in /usr/bin/php5)
==21278==    by 0x6DD6BA: dtrace_execute_internal (in /usr/bin/php5)
==21278==    by 0x79D714: ??? (in /usr/bin/php5)
==21278==    by 0x717447: execute_ex (in /usr/bin/php5)
==21278==    by 0x6DD5B8: dtrace_execute_ex (in /usr/bin/php5)
==21278==    by 0x6EF03F: zend_execute_scripts (in /usr/bin/php5)
==21278==    by 0x68EF24: php_execute_script (in /usr/bin/php5)
==21278==    by 0x79F6ED: ??? (in /usr/bin/php5)

 [2014-07-18 05:25 UTC] nurlan0000 at gmail dot com

I think I've found situation when the memory leak occurs. 
Memory is leaked only when you try to parse invalid date.
Here's example script:

for ( $i = 0; $i < 10000; $i++ ) {
    $d = DateTime::createFromFormat('m-d-Y', 'asdf asdf');
    unset($d);
    
    if ($i % 100 == 0) {
        echo 'Memory usage: ', memory_get_usage(), PHP_EOL;
    }
}

 [2022-07-27 06:17 UTC] rickychopra953 at gmail dot com

A touchless visitor management system is a safer way to handle the visitor sign-in process. It has some great features such as QR code and facial recognition which help in making your premises hygienic and capable to deter any infection.  


www.getveris.com/covid-visitor-screening-system

 [2024-03-16 02:04 UTC] jasminemercer1 at outlook dot com

0

Very unlikely a memory leak causes by a DateTime object. Generally, if an object is not Disposable and doesn't have event subscriptions (to a long lasting instance) it shouldn't be the root cause for a memory leak. Having said that you really need a proper tool (eg: RedGate Memory Profiler) to analyze memory leaks.

The code you have provided is not enough to say anything about the memory leak. However, keep in mind you MUST dispose all Disposable objects when you don't need them any more. Use 'using' when you are creating a local disposable object, it will dispose the instance when it is going out of the scope. Specially when you are using any kind of streams it is the best practice to wrap them within a using clause. It will close it and dispose for you(dispose actually closes the stream when disposing).

So, yes. Try disposing all disposable objects and test again. 'backData' object looks suspicious to me. Make sure you clear or dispose it appropriately.

https://ncedcloudam.com.github.com