diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-07-29 10:07:12 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-07-29 10:07:12 +0200 |
commit | 9bfda013d308b47610fb23ee565500418a9f3cde (patch) | |
tree | 32bb1c54097bfe07c19268f6afc19abbbd133768 | |
parent | fec71e3f25ebac450404e2035027d4344d556e9a (diff) | |
download | php-git-9bfda013d308b47610fb23ee565500418a9f3cde.tar.gz |
Fixed bug #78340
Even if we know the file size, we still need to read in a loop in
case the read call returns an incomplete result.
This was less of an issue previously because we did not use the
"one large read" approach for non-plain stream wrappers.
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | Zend/tests/bug78340.phpt | 54 | ||||
-rw-r--r-- | Zend/zend_stream.c | 20 |
3 files changed, 69 insertions, 9 deletions
@@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 7.4.0beta2 +- Core: + . Fixed bug #78340 (Include of stream wrapper not reading whole file). + (Nikita) + - Iconv: . Fixed bug #78342 (Bus error in configure test for iconv //IGNORE). (Rainer Jung) diff --git a/Zend/tests/bug78340.phpt b/Zend/tests/bug78340.phpt new file mode 100644 index 0000000000..06acf9ef88 --- /dev/null +++ b/Zend/tests/bug78340.phpt @@ -0,0 +1,54 @@ +--TEST-- +Bug #78340: Include of stream wrapper not reading whole file +--FILE-- +<?php + +class lib { + public static $files= []; + + private $bytes, $pos; + + function stream_open($path, $mode, $options, $opened_path) { + $this->bytes= self::$files[$path]; + $this->pos= 0; + $this->ino= crc32($path); + return true; + } + + function stream_read($count) { + $chunk= substr($this->bytes, $this->pos, $count); + $this->pos+= strlen($chunk); + return $chunk; + } + + function stream_eof() { + return $this->pos >= strlen($this->bytes); + } + + function stream_close() { + $this->bytes= null; + } + + function stream_stat() { + return [ + 'dev' => 3632233996, + 'size' => strlen($this->bytes), + 'ino' => $this->ino + ]; + } + + function stream_set_option($option, $arg1, $arg2) { + return false; + } +} + +$fill = str_repeat('.', 8192); +lib::$files['lib://test.php']= '<?php /* '.$fill.' */ function test() { echo "Works!\n"; }'; +stream_wrapper_register('lib', lib::class); + +include('lib://test.php'); +test(); + +?> +--EXPECT-- +Works! diff --git a/Zend/zend_stream.c b/Zend/zend_stream.c index 4dffc31040..3890248a26 100644 --- a/Zend/zend_stream.c +++ b/Zend/zend_stream.c @@ -115,7 +115,7 @@ static ssize_t zend_stream_read(zend_file_handle *file_handle, char *buf, size_t ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t *len) /* {{{ */ { - size_t size; + size_t file_size; if (file_handle->buf) { *buf = file_handle->buf; @@ -142,26 +142,28 @@ ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t file_handle->handle.stream.fsizer = (zend_stream_fsizer_t)zend_stream_stdio_fsizer; } - size = zend_stream_fsize(file_handle); - if (size == (size_t)-1) { + file_size = zend_stream_fsize(file_handle); + if (file_size == (size_t)-1) { return FAILURE; } - if (size) { + if (file_size) { ssize_t read; - *buf = safe_emalloc(1, size, ZEND_MMAP_AHEAD); - read = zend_stream_read(file_handle, *buf, size); + size_t size = 0; + *buf = safe_emalloc(1, file_size, ZEND_MMAP_AHEAD); + while ((read = zend_stream_read(file_handle, *buf + size, file_size - size)) > 0) { + size += read; + } if (read < 0) { efree(*buf); return FAILURE; } file_handle->buf = *buf; - file_handle->len = read; + file_handle->len = size; } else { - size_t remain = 4*1024; + size_t size = 0, remain = 4*1024; ssize_t read; *buf = emalloc(remain); - size = 0; while ((read = zend_stream_read(file_handle, *buf + size, remain)) > 0) { size += read; |