summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Wallner <mike@php.net>2014-04-02 15:36:39 +0200
committerMichael Wallner <mike@php.net>2014-04-02 15:36:39 +0200
commit1ec83d44a1601c3560f430e08af9698bf8fb075c (patch)
tree5a9e27c8134049c112fcd497d968afd8065c6ba3
parent91a9d24aa30507e6c7d8937db2de24394f0ce121 (diff)
downloadphp-git-1ec83d44a1601c3560f430e08af9698bf8fb075c.tar.gz
Fixed bug #61019 (Out of memory on command stream_get_contents)
-rw-r--r--NEWS1
-rw-r--r--ext/standard/tests/streams/bug61019.phpt78
-rw-r--r--main/streams/streams.c4
3 files changed, 83 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 51ed4f30ee..bc329ade53 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ PHP NEWS
?? ??? 2014, PHP 5.4.28
- Core:
+ . Fixed bug #61019 (Out of memory on command stream_get_contents). (Mike)
. Fixed bug #64330 (stream_socket_server() creates wrong Abstract Namespace
UNIX sockets). (Mike)
diff --git a/ext/standard/tests/streams/bug61019.phpt b/ext/standard/tests/streams/bug61019.phpt
new file mode 100644
index 0000000000..45b207ea9e
--- /dev/null
+++ b/ext/standard/tests/streams/bug61019.phpt
@@ -0,0 +1,78 @@
+--TEST--
+Bug #61019 (Out of memory on command stream_get_contents)
+--FILE--
+<?php
+
+echo "Test\n";
+
+$descriptorspec = array(
+ 0 => array("pipe", "r"), // stdin is a pipe that the child will read from
+ 1 => array("pipe", "w"), // stdout is a pipe that the child will write to
+ 2 => array("pipe", "w") // stderr is a pipe that the child will write to
+);
+
+$process=proc_open("echo testtext",$descriptorspec,$pipes);
+if(is_resource($process))
+{
+ stream_set_blocking($pipes[0],false);
+ stream_set_blocking($pipes[1],false);
+ stream_set_blocking($pipes[2],false);
+ stream_set_write_buffer($pipes[0],0);
+ stream_set_read_buffer($pipes[1],0);
+ stream_set_read_buffer($pipes[2],0);
+ $stdin_stream="";
+ $stderr_stream="";
+
+ echo "External command executed\n";
+ do
+ {
+ $process_state=proc_get_status($process);
+ $tmp_stdin=stream_get_contents($pipes[1]);
+ if($tmp_stdin)
+ {
+ $stdin_stream=$stdin_stream.$tmp_stdin;
+ }
+ $tmp_stderr=stream_get_contents($pipes[2]);
+ if($tmp_stderr)
+ {
+ $stderr_stream=$stderr_stream.$tmp_stderr;
+ }
+ } while($process_state['running']);
+
+ echo "External command exit: ".$process_state['exitcode']."\n";
+
+ //read outstanding data
+ $tmp_stdin=stream_get_contents($pipes[1]);
+ if($tmp_stdin)
+ {
+ $stdin_stream=$stdin_stream.$tmp_stdin;
+ }
+ $tmp_stderr=stream_get_contents($pipes[2]);
+ if($tmp_stderr)
+ {
+ $stderr_stream=$stderr_stream.$tmp_stderr;
+ }
+
+ fclose ($pipes[0]);
+ fclose ($pipes[1]);
+ fclose ($pipes[2]);
+
+ proc_close($process);
+
+ echo "STDOUT: ".$stdin_stream."\n";
+ echo "STDERR: ".$stderr_stream."\n";
+}
+else
+{
+ echo "Can't start external command\n";
+}
+?>
+===DONE===
+--EXPECT--
+Test
+External command executed
+External command exit: 0
+STDOUT: testtext
+
+STDERR:
+===DONE===
diff --git a/main/streams/streams.c b/main/streams/streams.c
index cac50ef03f..acc67dc207 100644
--- a/main/streams/streams.c
+++ b/main/streams/streams.c
@@ -736,6 +736,10 @@ PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS
if (!stream->readfilters.head && (stream->flags & PHP_STREAM_FLAG_NO_BUFFER || stream->chunk_size == 1)) {
toread = stream->ops->read(stream, buf, size TSRMLS_CC);
+ if (toread == (size_t) -1) {
+ /* e.g. underlying read(2) returned -1 */
+ break;
+ }
} else {
php_stream_fill_read_buffer(stream, size TSRMLS_CC);