php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #36427 proc_open() / proc_close() leak handles on Windows XP
Submitted: 2006-02-17 15:35 UTC Modified: 2006-12-31 15:29 UTC
Votes:5
Avg. Score:4.8 ± 0.4
Reproduced:4 of 4 (100.0%)
Same Version:2 (50.0%)
Same OS:3 (75.0%)
From: pgj at ds-fr dot com Assigned: wez
Status: Closed Package: Program Execution
PHP Version: 5.1.2, 4.4.2 OS: windows XP SP2 Windows 2000 SP4
Private report: No CVE-ID:
 [2006-02-17 15:35 UTC] pgj at ds-fr dot com
Description:
------------
I launch processes in a script and put stout in file
after more than 2000 processes and can't open a new one and have this message.
It's similar with 30743 bit it uses 2 pipes for $fileDescriptors and in this case it's a pipe and a file 


Reproduce code:
---------------
<?
set_time_limit(6000);
$i=0;
mkdir(test);
while(1)
{
  $i++;
	echo("-$i--\n");
	invoke($i);
}
function invoke($i)
{
	$commandLine = "echo hello";
	$fileDescriptors = array(
		1 => array("pipe", "r"),
		2 => array("file", "test/$i.txt","w")
		);
	$pipes = array();
	$processHandle	= proc_open($commandLine,$fileDescriptors, $pipes);
	if (is_resource($processHandle))
	{
  	fclose($pipes[1]);
    proc_close($processHandle);
	}
}



Expected result:
----------------
Open a new one

Actual result:
--------------
<b>Warning</b>:  proc_open(test/2587.txt): failed to open stream: Too many open files in <b>E:\cotcot\leak.php</b> on line <b>24</b><br />

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2006-02-19 01:38 UTC] nlopess@php.net
While I can reproduce the problem, I couldn't spot the error at first sight, because the code is very complex (and without valgrind even worst..)
 [2006-02-21 18:11 UTC] pgj at ds-fr dot com
Same problem with php 5.1.2
 [2006-05-28 20:57 UTC] jdolecek at NetBSD dot org
It appears the problem is actually due to way Windows internally emulate POSIX file descriptors, i.e. the process runs out of the allowed count of the 'POSIX' file descriptors tracked in the C library, not handles per se.

This is supported by Windows process viewer, which shows ~constant number of handles for PHP process during the script run, particularily same number of handles when it runs OK and when it starts giving the error.

Note the problem only appears when using 'file' in descriptorspec, using 'pipe' instead does workaround the problem.

I believe the problem can be fixed by consistently closing the file descriptors rather then just the handles, i.e something along:

--- ext/standard/proc_open.c.orig       2006-05-28 21:51:09.000000000 +0200
+++ ext/standard/proc_open.c
@@ -462,6 +462,9 @@ static inline HANDLE dup_fd_as_handle(in
 struct php_proc_open_descriptor_item {
        int index;                                                      /* desired fd number in child process */
        php_file_descriptor_t parentend, childend;      /* fds for pipes in parent/child */
+#ifdef PHP_WIN32
+    int childend_desc;
+#endif
        int mode;                                                       /* mode for proc_open code */
        int mode_flags;                                         /* mode flags for opening fds */
 };
@@ -671,6 +674,7 @@ PHP_FUNCTION(proc_open)

 #ifdef PHP_WIN32
                                descriptors[ndesc].childend = (HANDLE)_get_osfhandle(fd);
+                               descriptors[ndesc].childend_desc = fd;
 #else
                                descriptors[ndesc].childend = fd;
 #endif
@@ -901,6 +905,11 @@ PHP_FUNCTION(proc_open)
                char *mode_string=NULL;
                php_stream *stream = NULL;

+#ifdef PHP_WIN32
+               if (descriptors[i].childend_desc)
+                       _close(descriptors[i].childend_desc); /* closes also the handle */
+#endif
+
                close_descriptor(descriptors[i].childend);

                switch (descriptors[i].mode & ~DESC_PARENT_MODE_WRITE) {


I cannot check this, since I haven't succeeded in setting up a build environment on MS Windows for PHP sources.
 [2006-05-29 12:05 UTC] pgj at ds-fr dot com
Your correction works on 4.4.2 on windows, no more bugs after 10000 proc_open.
Thanks a lot
 [2006-06-01 16:13 UTC] jdolecek at NetBSD dot org
Alternative (simplier) patch:

--- ext/standard/proc_open.c.orig       2006-06-01 18:09:51.000000000 +0200
+++ ext/standard/proc_open.c
@@ -670,7 +670,10 @@ PHP_FUNCTION(proc_open)
                                }

 #ifdef PHP_WIN32
-                               descriptors[ndesc].childend = (HANDLE)_get_osfhandle(fd);
+                               /* dup the handle, and close the original descriptor to
+                                * avoid leak */
+                               descriptors[ndesc].childend = dup_fd_as_handle(fd);
+                               _close(fd);
 #else
                                descriptors[ndesc].childend = fd;
 #endif
 [2006-12-31 15:29 UTC] nlopess@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: Thu Apr 17 16:02:22 2014 UTC