summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph M. Becker <cmbecker69@gmx.de>2018-09-08 18:27:57 +0200
committerChristoph M. Becker <cmbecker69@gmx.de>2018-09-08 19:01:36 +0200
commit90d863898cd4d7a1e073916b4730aca33cc29184 (patch)
treed73e8f2f4299ed8a72be3d676d8cca911f78691e
parent28c6125053fa1b13bc88644f0e576ad620e1f0fb (diff)
downloadphp-git-90d863898cd4d7a1e073916b4730aca33cc29184.tar.gz
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.
-rw-r--r--NEWS4
-rw-r--r--ext/zlib/tests/bug75273.phpt58
-rw-r--r--ext/zlib/zlib_filter.c12
3 files changed, 64 insertions, 10 deletions
diff --git a/NEWS b/NEWS
index 50b9d68edd..10a8438963 100644
--- a/NEWS
+++ b/NEWS
@@ -19,6 +19,10 @@ PHP NEWS
. Fixed bug #74764 (Bindto IPv6 works with file_get_contents but fails with
stream_socket_client). (Ville Hukkamäki)
+- Zlib:
+ . Fixed bug #75273 (php_zlib_inflate_filter() may not update bytes_consumed).
+ (Martin Burke, cmb)
+
13 Sep 2018, PHP 7.1.22
- Core:
diff --git a/ext/zlib/tests/bug75273.phpt b/ext/zlib/tests/bug75273.phpt
new file mode 100644
index 0000000000..66ec81edff
--- /dev/null
+++ b/ext/zlib/tests/bug75273.phpt
@@ -0,0 +1,58 @@
+--TEST--
+Bug #75273 (php_zlib_inflate_filter() may not update bytes_consumed)
+--SKIPIF--
+<?php
+if (!extension_loaded('zlib')) die('skip zlib extension not available');
+?>
+--FILE--
+<?php
+function non_repeating_str($len = 8192) {
+ $ret = '';
+ mt_srand(1);
+ $iterations = (int) ($len / 256) + 1;
+ for ($i = 0; $i < $iterations; $i++) {
+ $haves = array();
+ $cnt = 0;
+ while ($cnt < 256) {
+ $j = mt_rand(0, 255);
+ if (!isset($haves[$j])) {
+ $haves[$j] = $j;
+ $cnt++;
+ $ret .= chr($j);
+ }
+ }
+ }
+ return substr($ret, 0, $len);
+}
+
+$base_len = 32768 - 23 /*overhead*/;
+
+$stream = fopen('php://memory', 'rb+');
+
+for ($i = 1; $i <= 8; $i++) {
+ $in_data = non_repeating_str($base_len + $i);
+
+ $deflate_filter = stream_filter_append($stream, 'zlib.deflate', STREAM_FILTER_WRITE, ['window' => 16 + 15]);
+ rewind($stream);
+ fwrite($stream, $in_data);
+ stream_filter_remove($deflate_filter);
+
+ rewind($stream);
+ $out_data = stream_get_contents($stream);
+ $out_data_len = strlen($out_data);
+
+ $inflate_filter = stream_filter_prepend($stream, 'zlib.inflate', STREAM_FILTER_WRITE, ['window' => 16 + 15]);
+ rewind($stream);
+ $fwrite_len = fwrite($stream, $out_data);
+ stream_filter_remove($inflate_filter);
+
+ if ($out_data_len !== $fwrite_len) {
+ echo "bug i=$i out_data_len=$out_data_len fwrite_len=$fwrite_len\n";
+ }
+}
+
+fclose($stream);
+?>
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/ext/zlib/zlib_filter.c b/ext/zlib/zlib_filter.c
index 8c40834d45..f3e0d9ad73 100644
--- a/ext/zlib/zlib_filter.c
+++ b/ext/zlib/zlib_filter.c
@@ -78,12 +78,7 @@ static php_stream_filter_status_t php_zlib_inflate_filter(
bucket = php_stream_bucket_make_writeable(buckets_in->head);
- while (bin < (unsigned int) bucket->buflen) {
-
- if (data->finished) {
- consumed += bucket->buflen;
- break;
- }
+ while (bin < (unsigned int) bucket->buflen && !data->finished) {
desired = bucket->buflen - bin;
if (desired > data->inbuf_len) {
@@ -96,6 +91,7 @@ static php_stream_filter_status_t php_zlib_inflate_filter(
if (status == Z_STREAM_END) {
inflateEnd(&(data->strm));
data->finished = '\1';
+ exit_status = PSFS_PASS_ON;
} else if (status != Z_OK) {
/* Something bad happened */
php_stream_bucket_delref(bucket);
@@ -118,10 +114,6 @@ static php_stream_filter_status_t php_zlib_inflate_filter(
data->strm.avail_out = data->outbuf_len;
data->strm.next_out = data->outbuf;
exit_status = PSFS_PASS_ON;
- } else if (status == Z_STREAM_END && data->strm.avail_out >= data->outbuf_len) {
- /* no more data to decompress, and nothing was spat out */
- php_stream_bucket_delref(bucket);
- return PSFS_PASS_ON;
}
}