diff options
author | Christoph M. Becker <cmbecker69@gmx.de> | 2021-02-16 19:36:37 +0100 |
---|---|---|
committer | Christoph M. Becker <cmbecker69@gmx.de> | 2021-02-22 15:28:46 +0100 |
commit | 963e50c8c48ecfbe7444445e5ca8e33530d630d0 (patch) | |
tree | bbd3603cc050f492eddb065e98a37ea3879a46fb /ext/bz2/bz2_filter.c | |
parent | 073b6ea818286fe838097d49f92ae379d5f217f0 (diff) | |
download | php-git-963e50c8c48ecfbe7444445e5ca8e33530d630d0.tar.gz |
Fix #75776: Flushing streams with compression filter is broken
First, the `bzip2.compress` filter has the same issue as `zlib.deflate`
so we port the respective fix[1] to ext/bz2.
Second, there is still an issue, if a stream with an attached
compression filter is flushed before it is closed, without any writes
in between. In that case, the compression is never finalized. We fix
this by enforcing a `_php_stream_flush()` with the `closing` flag set
in `_php_stream_free()`, whenever a write filter is attached. This
call is superfluous for most write filters, but does not hurt, even
when it is unnecessary.
[1] <http://git.php.net/?p=php-src.git;a=commit;h=20e75329f2adb11dd231852c061926d0e4080929>
Closes GH-6703.
Diffstat (limited to 'ext/bz2/bz2_filter.c')
-rw-r--r-- | ext/bz2/bz2_filter.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/ext/bz2/bz2_filter.c b/ext/bz2/bz2_filter.c index e7d7c3334f..fb79cb5dc6 100644 --- a/ext/bz2/bz2_filter.c +++ b/ext/bz2/bz2_filter.c @@ -41,6 +41,7 @@ typedef struct _php_bz2_filter_data { enum strm_status status; /* Decompress option */ unsigned int small_footprint : 1; /* Decompress option */ unsigned int expect_concatenated : 1; /* Decompress option */ + unsigned int is_flushed : 1; /* only for compression */ int persistent; } php_bz2_filter_data; @@ -228,6 +229,8 @@ static php_stream_filter_status_t php_bz2_compress_filter( bucket = php_stream_bucket_make_writeable(buckets_in->head); while (bin < bucket->buflen) { + int flush_mode; + desired = bucket->buflen - bin; if (desired > data->inbuf_len) { desired = data->inbuf_len; @@ -235,7 +238,9 @@ static php_stream_filter_status_t php_bz2_compress_filter( memcpy(data->strm.next_in, bucket->buf + bin, desired); data->strm.avail_in = desired; - status = BZ2_bzCompress(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : (flags & PSFS_FLAG_FLUSH_INC ? BZ_FLUSH : BZ_RUN)); + flush_mode = flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : (flags & PSFS_FLAG_FLUSH_INC ? BZ_FLUSH : BZ_RUN); + data->is_flushed = flush_mode != BZ_RUN; + status = BZ2_bzCompress(&(data->strm), flush_mode); if (status != BZ_RUN_OK && status != BZ_FLUSH_OK && status != BZ_FINISH_OK) { /* Something bad happened */ php_stream_bucket_delref(bucket); @@ -261,11 +266,12 @@ static php_stream_filter_status_t php_bz2_compress_filter( php_stream_bucket_delref(bucket); } - if (flags & PSFS_FLAG_FLUSH_CLOSE) { + if (flags & PSFS_FLAG_FLUSH_CLOSE || ((flags & PSFS_FLAG_FLUSH_INC) && !data->is_flushed)) { /* Spit it out! */ status = BZ_FINISH_OK; while (status == BZ_FINISH_OK) { - status = BZ2_bzCompress(&(data->strm), BZ_FINISH); + status = BZ2_bzCompress(&(data->strm), (flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : BZ_FLUSH)); + data->is_flushed = 1; if (data->strm.avail_out < data->outbuf_len) { size_t bucketlen = data->outbuf_len - data->strm.avail_out; @@ -381,6 +387,7 @@ static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *fi } status = BZ2_bzCompressInit(&(data->strm), blockSize100k, 0, workFactor); + data->is_flushed = 1; fops = &php_bz2_compress_ops; } else { status = BZ_DATA_ERROR; |