php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #47351 [PATCH] Memory leak in DateTime
Submitted: 2009-02-10 09:14 UTC Modified: 2009-06-30 16:18 UTC
Votes:5
Avg. Score:5.0 ± 0.0
Reproduced:5 of 5 (100.0%)
Same Version:2 (40.0%)
Same OS:2 (40.0%)
From: tobias dot john at fondsnet dot de Assigned: derick
Status: Closed Package: Date/time related
PHP Version: 5.*, 6CVS (2009-05-11) OS: *
Private report: No CVE-ID:
 [2009-02-10 09:14 UTC] tobias dot john at fondsnet dot de
Description:
------------
Memory allocated by a DateTime object is not released correctly. Inifite loops of allocating DateTime objects let the memory consumption even raise above the php memory limit.

Reproduce code:
---------------
while(1) {
    $v = new \DateTime();
}

Expected result:
----------------
Infinite loop.

Actual result:
--------------
php(38699) malloc: *** mmap(size=16777216) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
Bus error

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-02-23 13:49 UTC] paul dot assen at xs4all dot nl
I found this bug also to be present in PHP 5.2.8 under Windows XP
 [2009-03-05 17:39 UTC] bloudon at townnews dot com
Same bug found in PHP versions 5.2.8 and 5.2.9 on Linux.

-----

Test code:

for ( $i = 0; $i < 100; $i++ ) {
    $d = new DateTime();
    unset($d);
}

-----

valgrind --leak-check=yes php test.php:

==20642== 235 bytes in 1 blocks are possibly lost in loss record 4 of 12
==20642==    at 0x40203C0: malloc (vg_replace_malloc.c:149)
==20642==    by 0x80AB486: timelib_tzinfo_clone (in /usr/bin/php)
==20642==    by 0x8097FD3: timelib_fill_holes (in /usr/bin/php)
==20642==    by 0x8095535: (within /usr/bin/php)
==20642==    by 0x8095605: zim_DateTime___construct (in /usr/bin/php)
==20642==    by 0x817D834: (within /usr/bin/php)
==20642==    by 0x819ED4F: execute (in /usr/bin/php)
==20642==    by 0x8166F25: zend_execute_scripts (in /usr/bin/php)
==20642==    by 0x813862F: php_execute_script (in /usr/bin/php)
==20642==    by 0x81A7178: main (in /usr/bin/php)
==20642==
==20642==
==20642== 2,820 bytes in 3 blocks are possibly lost in loss record 8 of 12
==20642==    at 0x40203C0: malloc (vg_replace_malloc.c:149)
==20642==    by 0x80AB47A: timelib_tzinfo_clone (in /usr/bin/php)
==20642==    by 0x8097FD3: timelib_fill_holes (in /usr/bin/php)
==20642==    by 0x8095535: (within /usr/bin/php)
==20642==    by 0x8095605: zim_DateTime___construct (in /usr/bin/php)
==20642==    by 0x817D834: (within /usr/bin/php)
==20642==    by 0x819ED4F: execute (in /usr/bin/php)
==20642==    by 0x8166F25: zend_execute_scripts (in /usr/bin/php)
==20642==    by 0x813862F: php_execute_script (in /usr/bin/php)
==20642==    by 0x81A7178: main (in /usr/bin/php)
==20642==
==20642==
==20642== 132,845 (4,800 direct, 128,045 indirect) bytes in 100 blocks are definitely lost in loss record 9 of 12
==20642==    at 0x401F6FF: calloc (vg_replace_malloc.c:279)
==20642==    by 0x80AB420: timelib_tzinfo_ctor (in /usr/bin/php)
==20642==    by 0x80AB446: timelib_tzinfo_clone (in /usr/bin/php)
==20642==    by 0x8097FD3: timelib_fill_holes (in /usr/bin/php)
==20642==    by 0x8095535: (within /usr/bin/php)
==20642==    by 0x8095605: zim_DateTime___construct (in /usr/bin/php)
==20642==    by 0x817D834: (within /usr/bin/php)
==20642==    by 0x819ED4F: execute (in /usr/bin/php)
==20642==    by 0x8166F25: zend_execute_scripts (in /usr/bin/php)
==20642==    by 0x813862F: php_execute_script (in /usr/bin/php)
==20642==    by 0x81A7178: main (in /usr/bin/php)

-----

Setting a default time zone through date_default_timezone_set() or putenv() changes the leak to:

==20819== 7,600 (4,800 direct, 2,800 indirect) bytes in 100 blocks are definitely lost in loss record 10 of 10
==20819==    at 0x401F6FF: calloc (vg_replace_malloc.c:279)
==20819==    by 0x80AB420: timelib_tzinfo_ctor (in /usr/bin/php)
==20819==    by 0x80AB446: timelib_tzinfo_clone (in /usr/bin/php)
==20819==    by 0x8097FD3: timelib_fill_holes (in /usr/bin/php)
==20819==    by 0x8095535: (within /usr/bin/php)
==20819==    by 0x8095605: zim_DateTime___construct (in /usr/bin/php)
==20819==    by 0x817D834: (within /usr/bin/php)
==20819==    by 0x819ED4F: execute (in /usr/bin/php)
==20819==    by 0x8166F25: zend_execute_scripts (in /usr/bin/php)
==20819==    by 0x813862F: php_execute_script (in /usr/bin/php)
==20819==    by 0x81A7178: main (in /usr/bin/php)
 [2009-03-11 15:29 UTC] bloudon at townnews dot com
This patch against 5.2.9 seems to be working out for us so far:

--- ext/date/php_date.orig.c    2009-03-10 15:02:40.000000000 -0500
+++ ext/date/php_date.c 2009-03-10 15:02:57.000000000 -0500
@@ -1737,7 +1737,7 @@
    }
    timelib_unixtime2local(now, (timelib_sll) time(NULL));

-   timelib_fill_holes(dateobj->time, now, 0);
+   timelib_fill_holes(dateobj->time, now, TIMELIB_NO_CLONE);
    timelib_update_ts(dateobj->time, tzi);

    dateobj->time->have_weekday_relative = dateobj->time->have_relative = 0;
 [2009-05-07 10:06 UTC] tobias dot john at fondsnet dot de
I use this patch for 5.3.0RC1.

--- php-5.3.0RC1/ext/date/php_date.c	2009-01-27 14:48:10.000000000 +0100
+++ php-5.3.0RC1patched/ext/date/php_date.c	2009-05-07 10:54:48.000000000 +0200
@@ -2362,7 +2362,7 @@
 	}
 	timelib_unixtime2local(now, (timelib_sll) time(NULL));
 
-	timelib_fill_holes(dateobj->time, now, 0);
+	timelib_fill_holes(dateobj->time, now, TIMELIB_NO_CLONE);
 	timelib_update_ts(dateobj->time, tzi);
 
 	dateobj->time->have_relative = 0;
 [2009-06-22 12:05 UTC] tobias dot john at fondsnet dot de
Here is the patch for RC4. It would be nice if this makes it in before final, because this bug basically makes \DateTime more or less unuseable in longer running processes and processes that create and destroy many DateTime objects (like imports).

--- php-5.3.0RC3.orig/ext/date/php_date.c	2009-05-31 23:28:38.000000000 +0200
+++ php-5.3.0RC3/ext/date/php_date.c	2009-06-15 09:28:03.000000000 +0200
@@ -2401,7 +2401,7 @@
 	}
 	timelib_unixtime2local(now, (timelib_sll) time(NULL));
 
-	timelib_fill_holes(dateobj->time, now, 0);
+	timelib_fill_holes(dateobj->time, now, TIMELIB_NO_CLONE);
 	timelib_update_ts(dateobj->time, tzi);
 
 	dateobj->time->have_relative = 0;
 [2009-06-22 12:07 UTC] tobias dot john at fondsnet dot de
Sorry the previous post was the RC3 patch. Here is RC4.

--- php-5.3.0RC4.orig/ext/date/php_date.c	2009-06-17 19:56:17.000000000 +0200
+++ php-5.3.0RC4/ext/date/php_date.c	2009-06-22 13:57:49.000000000 +0200
@@ -2405,7 +2405,7 @@
 	}
 	timelib_unixtime2local(now, (timelib_sll) time(NULL));
 
-	timelib_fill_holes(dateobj->time, now, 0);
+	timelib_fill_holes(dateobj->time, now, TIMELIB_NO_CLONE);
 	timelib_update_ts(dateobj->time, tzi);
 
 	dateobj->time->have_relative = 0;
 [2009-06-30 12:30 UTC] tobias dot john at fondsnet dot de
Bug still not fixed in PHP 5.3.0 release.
 [2009-06-30 15:20 UTC] bloudon at townnews dot com
Updated patch for 5.3.0 final:

--- ext/date/php_date.orig.c    2009-06-30 09:46:19.000000000 -0500
+++ ext/date/php_date.c 2009-06-30 10:14:39.000000000 -0500
@@ -2414,7 +2414,7 @@
        }
        timelib_unixtime2local(now, (timelib_sll) time(NULL));

-       timelib_fill_holes(dateobj->time, now, 0);
+       timelib_fill_holes(dateobj->time, now, TIMELIB_NO_CLONE);
        timelib_update_ts(dateobj->time, tzi);

        dateobj->time->have_relative = 0;
 [2009-06-30 16:18 UTC] derick@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Wed Apr 23 17:01:58 2014 UTC