From 31749aac62a59fb215018ccb8099e1547182cdfc Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 26 Nov 2021 13:44:36 +0100 Subject: [PATCH] Fix #81659: stream_get_contents() may unnecessarily overallocate Since we're going to read from the current stream position anyway, the `max_len` should be the size of the file minus the current position (still catering to potentially filtered streams). We must, however, make sure to cater to the file position being beyond the actual file size. While we're at, we also fix the step size in the comment, which is 8K. A further optimization could be done for unfiltered streams, thus saving that step size, but 8K might not be worth it. Closes GH-7693. --- NEWS | 2 ++ ext/standard/tests/streams/bug81659.phpt | 24 ++++++++++++++++++++++++ main/streams/streams.c | 4 ++-- 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 ext/standard/tests/streams/bug81659.phpt diff --git a/NEWS b/NEWS index f17112179cf..0b46c1ad5c7 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,8 @@ PHP NEWS - Standard: . Fixed bug #81618 (dns_get_record fails on FreeBSD for missing type). (fsbruva) + . Fixed bug #81659 (stream_get_contents() may unnecessarily overallocate). + (cmb) 18 Nov 2021, PHP 7.4.26 diff --git a/ext/standard/tests/streams/bug81659.phpt b/ext/standard/tests/streams/bug81659.phpt new file mode 100644 index 00000000000..62e0cbad181 --- /dev/null +++ b/ext/standard/tests/streams/bug81659.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug #81659 (stream_get_contents() may unnecessarily overallocate) +--FILE-- + +--CLEAN-- + +--EXPECT-- +int(1024) +bool(true) diff --git a/main/streams/streams.c b/main/streams/streams.c index d2ee3371c9e..a320a90b525 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -1502,9 +1502,9 @@ PHPAPI zend_string *_php_stream_copy_to_mem(php_stream *src, size_t maxlen, int * result may be inaccurate, as the filter may inflate or deflate the * number of bytes that we can read. In order to avoid an upsize followed * by a downsize of the buffer, overestimate by the step size (which is - * 2K). */ + * 8K). */ if (php_stream_stat(src, &ssbuf) == 0 && ssbuf.sb.st_size > 0) { - max_len = ssbuf.sb.st_size + step; + max_len = MAX(ssbuf.sb.st_size - src->position, 0) + step; } else { max_len = step; }