]> granicus.if.org Git - php/commitdiff
- Fixed bug #61371 (resource leak). This bug had two parts, a long standing leak
authorGustavo André dos Santos Lopes <cataphract@php.net>
Sat, 17 Mar 2012 19:37:30 +0000 (19:37 +0000)
committerGustavo André dos Santos Lopes <cataphract@php.net>
Sat, 17 Mar 2012 19:37:30 +0000 (19:37 +0000)
  already fixed in trunk/5.3 and now merged onto 5.4 and a leak introduced in
  fixing bug #61115. This better fix for #61115 fixes the leak (the inhibition
  for deleting the context was too broad) and so prevents segfaults in new
  circumstances (where the inhibition was not broad enough).

ext/standard/streamsfuncs.c
ext/standard/tests/streams/bug61115-1.phpt [new file with mode: 0644]
ext/standard/tests/streams/bug61115-2.phpt [new file with mode: 0644]
ext/standard/tests/streams/bug61115.phpt [new file with mode: 0644]
ext/standard/tests/streams/bug61371.phpt [new file with mode: 0644]
main/streams/streams.c

index c903c57594892b10398dbce07bea09cbee6ad134..86e0bc6e604ef16e2c467a3628f54b9d9473d29d 100644 (file)
@@ -106,10 +106,6 @@ PHP_FUNCTION(stream_socket_client)
 
        context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
 
-       if (context) {
-               zend_list_addref(context->rsrc_id);
-       }
-
        if (flags & PHP_STREAM_CLIENT_PERSISTENT) {
                spprintf(&hashkey, 0, "stream_socket_client__%s", host);
        }
diff --git a/ext/standard/tests/streams/bug61115-1.phpt b/ext/standard/tests/streams/bug61115-1.phpt
new file mode 100644 (file)
index 0000000..43c54b4
--- /dev/null
@@ -0,0 +1,11 @@
+--TEST--
+Bug #61115: Stream related segfault on fatal error in php_stream_context_del_link - variation 1
+--FILE--
+<?php
+
+$fileResourceTemp = fopen('php://temp', 'wr');
+stream_context_get_options($fileResourceTemp);
+ftruncate($fileResourceTemp, PHP_INT_MAX);
+?>
+--EXPECTF--
+Fatal error: Allowed memory size of %d bytes exhausted at %s:%d (tried to allocate %d bytes) in %s on line %d
diff --git a/ext/standard/tests/streams/bug61115-2.phpt b/ext/standard/tests/streams/bug61115-2.phpt
new file mode 100644 (file)
index 0000000..260b836
--- /dev/null
@@ -0,0 +1,10 @@
+--TEST--
+Bug #61115: Stream related segfault on fatal error in php_stream_context_del_link - variation 2
+--FILE--
+<?php
+stream_socket_client('abc', $var, $var, 0, STREAM_CLIENT_PERSISTENT);
+
+?>
+==DONE==
+--EXPECT--
+==DONE==
diff --git a/ext/standard/tests/streams/bug61115.phpt b/ext/standard/tests/streams/bug61115.phpt
new file mode 100644 (file)
index 0000000..29dc7c1
--- /dev/null
@@ -0,0 +1,13 @@
+--TEST--
+Bug #61115: Stream related segfault on fatal error in php_stream_context_del_link.
+--FILE--
+<?php
+
+$arrayLarge = array_fill(0, 113663, '*');
+
+$resourceFileTemp = fopen('php://temp', 'r+');
+stream_context_set_params($resourceFileTemp, array());
+preg_replace('', function() {}, $resourceFileTemp);
+?>
+--EXPECTF--
+Catchable fatal error: Object of class Closure could not be converted to string in %s on line %d
diff --git a/ext/standard/tests/streams/bug61371.phpt b/ext/standard/tests/streams/bug61371.phpt
new file mode 100644 (file)
index 0000000..7fbfa56
--- /dev/null
@@ -0,0 +1,40 @@
+--TEST--
+Bug #61371: stream_context_create() causes memory leaks on use streams_socket_create
+--FILE--
+<?php
+function test($doFclose) {
+$previous = null;
+$current = null;
+for($test=1;$test<=3;$test++) {
+       $current = memory_get_usage(true);
+       if (!is_null($previous)) {
+               var_dump($previous == $current);
+       }
+       $previous = $current;
+       echo 'memory: '.round($current / 1024, 0)."kb\n";
+       for($i=0;$i<=100;$i++) {
+               $context = stream_context_create(array());
+               $stream = stream_socket_client('udp://0.0.0.0:80', $errno, $errstr, 10, STREAM_CLIENT_CONNECT, $context);
+               if ($doFclose) fclose($stream);
+               unset($context);
+               unset($stream);
+               unset($errno);
+               unset($errstr);
+       }
+}
+}
+
+test(true);
+test(false);
+?>
+--EXPECTF--
+memory: %dkb
+bool(true)
+memory: %dkb
+bool(true)
+memory: %dkb
+memory: %dkb
+bool(true)
+memory: %dkb
+bool(true)
+memory: %dkb
index 390db1d1ce59b82b09197fd0d7ab93b03d16f5df..161430754e74dff3810eaa0c13b47301762fd69f 100755 (executable)
@@ -385,7 +385,14 @@ PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /*
        int ret = 1;
        int preserve_handle = close_options & PHP_STREAM_FREE_PRESERVE_HANDLE ? 1 : 0;
        int release_cast = 1;
-       php_stream_context *context = stream->context;
+       php_stream_context *context = NULL;
+
+       /* on an resource list destruction, the context, another resource, may have
+        * already been freed (if it was created after the stream resource), so
+        * don't reference it */
+       if (EG(active)) {
+               context = stream->context;
+       }
 
        if (stream->flags & PHP_STREAM_FLAG_NO_CLOSE) {
                preserve_handle = 1;
@@ -464,8 +471,8 @@ fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remov
        }
 
        /* Remove stream from any context link list */
-       if (stream->context && stream->context->links) {
-               php_stream_context_del_link(stream->context, stream);
+       if (context && context->links) {
+               php_stream_context_del_link(context, stream);
        }
 
        if (close_options & PHP_STREAM_FREE_CALL_DTOR) {