Skip to content

Commit d974e44

Browse files
committed
- Fixed bug #61371 (resource leak). This bug had two parts, a long standing leak
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).
1 parent 9bfe801 commit d974e44

File tree

6 files changed

+84
-7
lines changed

6 files changed

+84
-7
lines changed

ext/standard/streamsfuncs.c

-4
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,6 @@ PHP_FUNCTION(stream_socket_client)
106106

107107
context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
108108

109-
if (context) {
110-
zend_list_addref(context->rsrc_id);
111-
}
112-
113109
if (flags & PHP_STREAM_CLIENT_PERSISTENT) {
114110
spprintf(&hashkey, 0, "stream_socket_client__%s", host);
115111
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
--TEST--
2+
Bug #61115: Stream related segfault on fatal error in php_stream_context_del_link - variation 1
3+
--FILE--
4+
<?php
5+
6+
$fileResourceTemp = fopen('php://temp', 'wr');
7+
stream_context_get_options($fileResourceTemp);
8+
ftruncate($fileResourceTemp, PHP_INT_MAX);
9+
?>
10+
--EXPECTF--
11+
Fatal error: Allowed memory size of %d bytes exhausted at %s:%d (tried to allocate %d bytes) in %s on line %d
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
Bug #61115: Stream related segfault on fatal error in php_stream_context_del_link - variation 2
3+
--FILE--
4+
<?php
5+
stream_socket_client('abc', $var, $var, 0, STREAM_CLIENT_PERSISTENT);
6+
7+
?>
8+
==DONE==
9+
--EXPECT--
10+
==DONE==
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
Bug #61115: Stream related segfault on fatal error in php_stream_context_del_link.
3+
--FILE--
4+
<?php
5+
6+
$arrayLarge = array_fill(0, 113663, '*');
7+
8+
$resourceFileTemp = fopen('php://temp', 'r+');
9+
stream_context_set_params($resourceFileTemp, array());
10+
preg_replace('', function() {}, $resourceFileTemp);
11+
?>
12+
--EXPECTF--
13+
Catchable fatal error: Object of class Closure could not be converted to string in %s on line %d
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
Bug #61371: stream_context_create() causes memory leaks on use streams_socket_create
3+
--FILE--
4+
<?php
5+
function test($doFclose) {
6+
$previous = null;
7+
$current = null;
8+
for($test=1;$test<=3;$test++) {
9+
$current = memory_get_usage(true);
10+
if (!is_null($previous)) {
11+
var_dump($previous == $current);
12+
}
13+
$previous = $current;
14+
echo 'memory: '.round($current / 1024, 0)."kb\n";
15+
for($i=0;$i<=100;$i++) {
16+
$context = stream_context_create(array());
17+
$stream = stream_socket_client('udp://0.0.0.0:80', $errno, $errstr, 10, STREAM_CLIENT_CONNECT, $context);
18+
if ($doFclose) fclose($stream);
19+
unset($context);
20+
unset($stream);
21+
unset($errno);
22+
unset($errstr);
23+
}
24+
}
25+
}
26+
27+
test(true);
28+
test(false);
29+
?>
30+
--EXPECTF--
31+
memory: %dkb
32+
bool(true)
33+
memory: %dkb
34+
bool(true)
35+
memory: %dkb
36+
memory: %dkb
37+
bool(true)
38+
memory: %dkb
39+
bool(true)
40+
memory: %dkb

main/streams/streams.c

+10-3
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,14 @@ PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /*
385385
int ret = 1;
386386
int preserve_handle = close_options & PHP_STREAM_FREE_PRESERVE_HANDLE ? 1 : 0;
387387
int release_cast = 1;
388-
php_stream_context *context = stream->context;
388+
php_stream_context *context = NULL;
389+
390+
/* on an resource list destruction, the context, another resource, may have
391+
* already been freed (if it was created after the stream resource), so
392+
* don't reference it */
393+
if (EG(active)) {
394+
context = stream->context;
395+
}
389396

390397
if (stream->flags & PHP_STREAM_FLAG_NO_CLOSE) {
391398
preserve_handle = 1;
@@ -464,8 +471,8 @@ fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remov
464471
}
465472

466473
/* Remove stream from any context link list */
467-
if (stream->context && stream->context->links) {
468-
php_stream_context_del_link(stream->context, stream);
474+
if (context && context->links) {
475+
php_stream_context_del_link(context, stream);
469476
}
470477

471478
if (close_options & PHP_STREAM_FREE_CALL_DTOR) {

0 commit comments

Comments
 (0)