Skip to content

Commit 90d8638

Browse files
committed
Fix #75273: php_zlib_inflate_filter() may not update bytes_consumed
Whenever we return with `PSFS_PASS_ON`, we need to update `bytes_consumed` to not mislead the caller. Instead of fixing the respective `if` clauses, we eschew the early bail-outs to simplify the code a bit.
1 parent 28c6125 commit 90d8638

File tree

3 files changed

+64
-10
lines changed

3 files changed

+64
-10
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ PHP NEWS
1919
. Fixed bug #74764 (Bindto IPv6 works with file_get_contents but fails with
2020
stream_socket_client). (Ville Hukkamäki)
2121

22+
- Zlib:
23+
. Fixed bug #75273 (php_zlib_inflate_filter() may not update bytes_consumed).
24+
(Martin Burke, cmb)
25+
2226
13 Sep 2018, PHP 7.1.22
2327

2428
- Core:

ext/zlib/tests/bug75273.phpt

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
Bug #75273 (php_zlib_inflate_filter() may not update bytes_consumed)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('zlib')) die('skip zlib extension not available');
6+
?>
7+
--FILE--
8+
<?php
9+
function non_repeating_str($len = 8192) {
10+
$ret = '';
11+
mt_srand(1);
12+
$iterations = (int) ($len / 256) + 1;
13+
for ($i = 0; $i < $iterations; $i++) {
14+
$haves = array();
15+
$cnt = 0;
16+
while ($cnt < 256) {
17+
$j = mt_rand(0, 255);
18+
if (!isset($haves[$j])) {
19+
$haves[$j] = $j;
20+
$cnt++;
21+
$ret .= chr($j);
22+
}
23+
}
24+
}
25+
return substr($ret, 0, $len);
26+
}
27+
28+
$base_len = 32768 - 23 /*overhead*/;
29+
30+
$stream = fopen('php://memory', 'rb+');
31+
32+
for ($i = 1; $i <= 8; $i++) {
33+
$in_data = non_repeating_str($base_len + $i);
34+
35+
$deflate_filter = stream_filter_append($stream, 'zlib.deflate', STREAM_FILTER_WRITE, ['window' => 16 + 15]);
36+
rewind($stream);
37+
fwrite($stream, $in_data);
38+
stream_filter_remove($deflate_filter);
39+
40+
rewind($stream);
41+
$out_data = stream_get_contents($stream);
42+
$out_data_len = strlen($out_data);
43+
44+
$inflate_filter = stream_filter_prepend($stream, 'zlib.inflate', STREAM_FILTER_WRITE, ['window' => 16 + 15]);
45+
rewind($stream);
46+
$fwrite_len = fwrite($stream, $out_data);
47+
stream_filter_remove($inflate_filter);
48+
49+
if ($out_data_len !== $fwrite_len) {
50+
echo "bug i=$i out_data_len=$out_data_len fwrite_len=$fwrite_len\n";
51+
}
52+
}
53+
54+
fclose($stream);
55+
?>
56+
===DONE===
57+
--EXPECT--
58+
===DONE===

ext/zlib/zlib_filter.c

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,7 @@ static php_stream_filter_status_t php_zlib_inflate_filter(
7878

7979
bucket = php_stream_bucket_make_writeable(buckets_in->head);
8080

81-
while (bin < (unsigned int) bucket->buflen) {
82-
83-
if (data->finished) {
84-
consumed += bucket->buflen;
85-
break;
86-
}
81+
while (bin < (unsigned int) bucket->buflen && !data->finished) {
8782

8883
desired = bucket->buflen - bin;
8984
if (desired > data->inbuf_len) {
@@ -96,6 +91,7 @@ static php_stream_filter_status_t php_zlib_inflate_filter(
9691
if (status == Z_STREAM_END) {
9792
inflateEnd(&(data->strm));
9893
data->finished = '\1';
94+
exit_status = PSFS_PASS_ON;
9995
} else if (status != Z_OK) {
10096
/* Something bad happened */
10197
php_stream_bucket_delref(bucket);
@@ -118,10 +114,6 @@ static php_stream_filter_status_t php_zlib_inflate_filter(
118114
data->strm.avail_out = data->outbuf_len;
119115
data->strm.next_out = data->outbuf;
120116
exit_status = PSFS_PASS_ON;
121-
} else if (status == Z_STREAM_END && data->strm.avail_out >= data->outbuf_len) {
122-
/* no more data to decompress, and nothing was spat out */
123-
php_stream_bucket_delref(bucket);
124-
return PSFS_PASS_ON;
125117
}
126118

127119
}

0 commit comments

Comments
 (0)