From fcec48fcc2adac254d9f54fc91f406ea6ab84465 Mon Sep 17 00:00:00 2001 From: Greg Beaver Date: Sat, 11 Oct 2008 19:12:11 +0000 Subject: [PATCH] fix Bug #46026: bz2.decompress/zlib.inflate filter tries to decompress after end of stream --- NEWS | 2 ++ ext/bz2/bz2_filter.c | 20 +++++++++++++++++--- ext/zlib/zlib_filter.c | 19 ++++++++++++++++--- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index d9351dea0b..2c574a1f4c 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,8 @@ PHP NEWS and $this->$method()). (Dmitry) - Fixed bug #46139 (PDOStatement->setFetchMode() forgets FETCH_PROPS_LATE). (chsc at peytz dot dk, Felipe) +- Fixed bug #46026 (bzip2.decompress/zlib.inflate filter tries to decompress + after end of stream). (Keisial at gmail dot com, Greg) - Fixed bug #44251, #41125 (PDO + quote() + prepare() can result in seg fault). (tsteiner at nerdclub dot net) diff --git a/ext/bz2/bz2_filter.c b/ext/bz2/bz2_filter.c index 5c986fc5a8..07597e5b18 100644 --- a/ext/bz2/bz2_filter.c +++ b/ext/bz2/bz2_filter.c @@ -34,6 +34,7 @@ typedef struct _php_bz2_filter_data { size_t inbuf_len; char *outbuf; size_t outbuf_len; + zend_bool finished; } php_bz2_filter_data; /* }}} */ @@ -82,6 +83,11 @@ static php_stream_filter_status_t php_bz2_decompress_filter( bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC); while (bin < bucket->buflen) { + if (data->finished) { + consumed += bucket->buflen; + break; + } + desired = bucket->buflen - bin; if (desired > data->inbuf_len) { desired = data->inbuf_len; @@ -90,7 +96,11 @@ static php_stream_filter_status_t php_bz2_decompress_filter( data->strm.avail_in = desired; status = BZ2_bzDecompress(&(data->strm)); - if (status != BZ_OK && status != BZ_STREAM_END) { + + if (status == BZ_STREAM_END) { + BZ2_bzDecompressEnd(&(data->strm)); + data->finished = '\1'; + } else if (status != BZ_OK) { /* Something bad happened */ php_stream_bucket_delref(bucket TSRMLS_CC); return PSFS_ERR_FATAL; @@ -115,10 +125,11 @@ static php_stream_filter_status_t php_bz2_decompress_filter( return PSFS_PASS_ON; } } + php_stream_bucket_delref(bucket TSRMLS_CC); } - if (flags & PSFS_FLAG_FLUSH_CLOSE) { + if (!data->finished && (flags & PSFS_FLAG_FLUSH_CLOSE)) { /* Spit it out! */ status = BZ_OK; while (status == BZ_OK) { @@ -148,7 +159,9 @@ static void php_bz2_decompress_dtor(php_stream_filter *thisfilter TSRMLS_DC) { if (thisfilter && thisfilter->abstract) { php_bz2_filter_data *data = thisfilter->abstract; - BZ2_bzDecompressEnd(&(data->strm)); + if (!data->finished) { + BZ2_bzDecompressEnd(&(data->strm)); + } pefree(data->inbuf, data->persistent); pefree(data->outbuf, data->persistent); pefree(data, data->persistent); @@ -327,6 +340,7 @@ static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *fi } status = BZ2_bzDecompressInit(&(data->strm), 0, smallFootprint); + data->finished = '\0'; fops = &php_bz2_decompress_ops; } else if (strcasecmp(filtername, "bzip2.compress") == 0) { int blockSize100k = PHP_BZ2_FILTER_DEFAULT_BLOCKSIZE; diff --git a/ext/zlib/zlib_filter.c b/ext/zlib/zlib_filter.c index ac1c029a40..8d804989c5 100644 --- a/ext/zlib/zlib_filter.c +++ b/ext/zlib/zlib_filter.c @@ -31,6 +31,7 @@ typedef struct _php_zlib_filter_data { size_t inbuf_len; char *outbuf; size_t outbuf_len; + zend_bool finished; } php_zlib_filter_data; /* }}} */ @@ -81,6 +82,12 @@ static php_stream_filter_status_t php_zlib_inflate_filter( bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC); while (bin < bucket->buflen) { + + if (data->finished) { + consumed += bucket->buflen; + break; + } + desired = bucket->buflen - bin; if (desired > data->inbuf_len) { desired = data->inbuf_len; @@ -89,7 +96,10 @@ static php_stream_filter_status_t php_zlib_inflate_filter( data->strm.avail_in = desired; status = inflate(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? Z_FINISH : Z_SYNC_FLUSH); - if (status != Z_OK && status != Z_STREAM_END) { + if (status == Z_STREAM_END) { + inflateEnd(&(data->strm)); + data->finished = '\1'; + } else if (status != Z_OK) { /* Something bad happened */ php_stream_bucket_delref(bucket TSRMLS_CC); return PSFS_ERR_FATAL; @@ -118,7 +128,7 @@ static php_stream_filter_status_t php_zlib_inflate_filter( php_stream_bucket_delref(bucket TSRMLS_CC); } - if (flags & PSFS_FLAG_FLUSH_CLOSE) { + if (!data->finished && flags & PSFS_FLAG_FLUSH_CLOSE) { /* Spit it out! */ status = Z_OK; while (status == Z_OK) { @@ -146,7 +156,9 @@ static void php_zlib_inflate_dtor(php_stream_filter *thisfilter TSRMLS_DC) { if (thisfilter && thisfilter->abstract) { php_zlib_filter_data *data = thisfilter->abstract; - inflateEnd(&(data->strm)); + if (!data->finished) { + inflateEnd(&(data->strm)); + } pefree(data->inbuf, data->persistent); pefree(data->outbuf, data->persistent); pefree(data, data->persistent); @@ -330,6 +342,7 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f } /* RFC 1951 Inflate */ + data->finished = '\0'; status = inflateInit2(&(data->strm), windowBits); fops = &php_zlib_inflate_ops; } else if (strcasecmp(filtername, "zlib.deflate") == 0) { -- 2.50.1