Skip to content

Commit 9bfda01

Browse files
committed
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.
1 parent fec71e3 commit 9bfda01

File tree

3 files changed

+69
-9
lines changed

3 files changed

+69
-9
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 7.4.0beta2
44

5+
- Core:
6+
. Fixed bug #78340 (Include of stream wrapper not reading whole file).
7+
(Nikita)
8+
59
- Iconv:
610
. Fixed bug #78342 (Bus error in configure test for iconv //IGNORE). (Rainer
711
Jung)

Zend/tests/bug78340.phpt

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
--TEST--
2+
Bug #78340: Include of stream wrapper not reading whole file
3+
--FILE--
4+
<?php
5+
6+
class lib {
7+
public static $files= [];
8+
9+
private $bytes, $pos;
10+
11+
function stream_open($path, $mode, $options, $opened_path) {
12+
$this->bytes= self::$files[$path];
13+
$this->pos= 0;
14+
$this->ino= crc32($path);
15+
return true;
16+
}
17+
18+
function stream_read($count) {
19+
$chunk= substr($this->bytes, $this->pos, $count);
20+
$this->pos+= strlen($chunk);
21+
return $chunk;
22+
}
23+
24+
function stream_eof() {
25+
return $this->pos >= strlen($this->bytes);
26+
}
27+
28+
function stream_close() {
29+
$this->bytes= null;
30+
}
31+
32+
function stream_stat() {
33+
return [
34+
'dev' => 3632233996,
35+
'size' => strlen($this->bytes),
36+
'ino' => $this->ino
37+
];
38+
}
39+
40+
function stream_set_option($option, $arg1, $arg2) {
41+
return false;
42+
}
43+
}
44+
45+
$fill = str_repeat('.', 8192);
46+
lib::$files['lib://test.php']= '<?php /* '.$fill.' */ function test() { echo "Works!\n"; }';
47+
stream_wrapper_register('lib', lib::class);
48+
49+
include('lib://test.php');
50+
test();
51+
52+
?>
53+
--EXPECT--
54+
Works!

Zend/zend_stream.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ static ssize_t zend_stream_read(zend_file_handle *file_handle, char *buf, size_t
115115

116116
ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t *len) /* {{{ */
117117
{
118-
size_t size;
118+
size_t file_size;
119119

120120
if (file_handle->buf) {
121121
*buf = file_handle->buf;
@@ -142,26 +142,28 @@ ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t
142142
file_handle->handle.stream.fsizer = (zend_stream_fsizer_t)zend_stream_stdio_fsizer;
143143
}
144144

145-
size = zend_stream_fsize(file_handle);
146-
if (size == (size_t)-1) {
145+
file_size = zend_stream_fsize(file_handle);
146+
if (file_size == (size_t)-1) {
147147
return FAILURE;
148148
}
149149

150-
if (size) {
150+
if (file_size) {
151151
ssize_t read;
152-
*buf = safe_emalloc(1, size, ZEND_MMAP_AHEAD);
153-
read = zend_stream_read(file_handle, *buf, size);
152+
size_t size = 0;
153+
*buf = safe_emalloc(1, file_size, ZEND_MMAP_AHEAD);
154+
while ((read = zend_stream_read(file_handle, *buf + size, file_size - size)) > 0) {
155+
size += read;
156+
}
154157
if (read < 0) {
155158
efree(*buf);
156159
return FAILURE;
157160
}
158161
file_handle->buf = *buf;
159-
file_handle->len = read;
162+
file_handle->len = size;
160163
} else {
161-
size_t remain = 4*1024;
164+
size_t size = 0, remain = 4*1024;
162165
ssize_t read;
163166
*buf = emalloc(remain);
164-
size = 0;
165167

166168
while ((read = zend_stream_read(file_handle, *buf + size, remain)) > 0) {
167169
size += read;

0 commit comments

Comments
 (0)