php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #50111 memory not properly freed when stream_context_create is used (PHP_5_2 only!)
Submitted: 2009-11-07 09:26 UTC Modified: 2009-11-19 15:45 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:0 (0.0%)
From: datibbaw@php.net Assigned:
Status: Wont fix Package: Streams related
PHP Version: 5.2.11 OS: Linux
Private report: No CVE-ID: None
 [2009-11-07 09:26 UTC] datibbaw@php.net
Description:
------------
When stream_context_create() is used in conjunction with file_get_contents() or other stream related functions that accept a context parameter, memory is being leaked.

Reproduce code:
---------------
for ($i=0;$i<5;++$i){
  $m0 = memory_get_usage();
  file_get_contents('http://www.google.com', false, stream_context_create(array()));
  $m1 = memory_get_usage();
  echo $m1-$m0,PHP_EOL;
}

Expected result:
----------------
X (where X is the memory increase for the first iterator)
0
0
0
0


Actual result:
--------------
X (where X is the memory increase for the first iterator)
384 (or something similar)
420
420
480

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-11-08 01:06 UTC] datibbaw@php.net
Code to reproduce can be made simpler, since the problem seems to be with stream_context_create():

$m0 = $m1 = $i = 0;
$c = null;
while ($i<5) {
    $m0 = memory_get_usage();
    $c = stream_context_create();
    $m1 = memory_get_usage();
    echo $m1-$m0,PHP_EOL;
    ++$i;
}
 [2009-11-08 21:17 UTC] srinatar@php.net
hmmm.. not sure, why u think there is a leak.

when u write this below code
$c = stream_context_create();

u do understand that underlying php engine need to do some processing  
underneath and store the reference of this processing in $c variable. 
this does require some memory consumption. 

i guess, if u do some thing like and still no
$c = stream_context_create..
unset($c);
$m1 = memory_get_usage();

and still see memory leak , then let us know..
 [2009-11-08 23:27 UTC] datibbaw@php.net
Test code changed to (added the unset() statement):

$m0 = $m1 = $i = 0;
$c = null;
while ($i<5) {
    $m0 = memory_get_usage();
    $c = stream_context_create();
    unset($c);
    $m1 = memory_get_usage();
    echo $m1-$m0,PHP_EOL;
    ++$i;
}

Output:
336
420
420
420
420

Though, as a language feature I would assume that in the second iteration the memory occupied by the previous assignment would be freed implicitly. Is that a wrong assumption?
 [2009-11-09 17:11 UTC] jani@php.net
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


 [2009-11-18 14:05 UTC] datibbaw@php.net
I've change the summary a bit to avoid confusion with an actual memory leak (those that would get reported by php at the end of execution in debug mode).

When kept running (using cli), an endless loop of given code would eventually result in an out-of-memory error.

In PHP 5.3.x this no longer happens, so it seems that this has been rectified before, just not in this branch. It would be nice if the same fix could be applied here.
 [2009-11-18 18:14 UTC] jani@php.net
What code? There is no such script in this report that crashes. Not even when changed to loop thousands of times. Not with PHP_5_2 or PHP_5_3 or HEAD branches. So please, come up with a proper reproducing script.
 [2009-11-18 22:03 UTC] datibbaw@php.net
<?php

echo "This is PHP ", phpversion(),PHP_EOL;
ini_set("memory_limit", "0");

for ($i=0;$i<2000;++$i) {
  $x = stream_context_create(array());
  unset($x);
}
echo "Done", PHP_EOL;

?>
----------------
$ /usr/local/php-5.1.0/bin/php lala.php
This is PHP 5.1.0
Done
----------------
$ /usr/local/php-5.1.1/bin/php lala.php
This is PHP 5.1.1
Done
----------------
$ /usr/local/php-5.1.2/bin/php lala.php
This is PHP 5.1.2
Done
----------------
$ /usr/local/php-5.2.9/bin/php lala.php
This is PHP 5.2.9

Fatal error: Allowed memory size of 262144 bytes exhausted at /usr/local/src/php-5.2.9/Zend/zend_list.c:47 (tried to allocate 12 bytes) in /home/tjerk/lala.php on line 7
----------------
$ /usr/local/php-5.2.11/bin/php lala.php
This is PHP 5.2.11

Fatal error: Allowed memory size of 262144 bytes exhausted at /usr/local/src/php-5.2.11/main/streams/streams.c:1945 (tried to allocate 16 bytes) in /home/tjerk/lala.php on line 7
----------------
$ /usr/local/php-5.3/bin/php lala.php
This is PHP 5.3.0RC3-dev
Done
 [2009-11-19 09:38 UTC] jani@php.net
To disable memory_limit, you need to set it to -1, not 0.
 [2009-11-19 13:39 UTC] datibbaw@php.net
I'm not trying to disable memory_limit. Setting it to "0" just happens to make the issue appear faster.

Changing it to the below value of 1k yields the same results as mentioned earlier, tested on the same 5 php configurations:

ini_set("memory_limit", "1000");

 [2009-11-19 15:28 UTC] datibbaw@php.net
My results for PHP 5.1.x were wrong, because I didn't compile them with --enable-memory-limit, so the ini_set() wasn't actually working for those; guess it was automatically added in 5.2.x even in the presence of --disable-all ... my bad =(

After some more research on the PHP code itself, the problem seems to lie in the fact that the following two functions are called by stream_context_create():
zend_list_insert() - called by php_stream_context_alloc()
zend_list_addref() - called by php_stream_context_to_zval()

This results in a refcount of 2 for each context returned. This has changed in 5.3.x but not sure in how many places ;-)
 [2009-11-19 15:45 UTC] jani@php.net
PHP 5.3 has better garbage collection, hence this works there and not in 5.2, wont fix for 5.2.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Dec 02 23:01:29 2024 UTC