From: Greg Beaver Date: Sat, 11 Oct 2008 19:14:48 +0000 (+0000) Subject: MFB fix Bug #46026: bz2.decompress/zlib.inflate filter tries to decompress after... X-Git-Tag: BEFORE_HEAD_NS_CHANGE~251 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=236f646bab2ed160cc2c318f252a7122998e0c3f;p=php MFB fix Bug #46026: bz2.decompress/zlib.inflate filter tries to decompress after end of stream MFB add concatenation option to bz2.decompress stream filter --- diff --git a/ext/bz2/bz2_filter.c b/ext/bz2/bz2_filter.c index b0b2c6586d..022d84a7cf 100644 --- a/ext/bz2/bz2_filter.c +++ b/ext/bz2/bz2_filter.c @@ -27,6 +27,12 @@ /* {{{ data structure */ +enum strm_status { + PHP_BZ2_UNITIALIZED, + PHP_BZ2_RUNNING, + PHP_BZ2_FINISHED +}; + typedef struct _php_bz2_filter_data { int persistent; bz_stream strm; @@ -34,6 +40,11 @@ typedef struct _php_bz2_filter_data { size_t inbuf_len; char *outbuf; size_t outbuf_len; + + /* Decompress options */ + enum strm_status status; + unsigned int small_footprint : 1; + unsigned int expect_concatenated : 1; } php_bz2_filter_data; /* }}} */ @@ -89,6 +100,21 @@ static php_stream_filter_status_t php_bz2_decompress_filter( bucket = php_stream_bucket_make_writeable(bucket TSRMLS_CC); while (bin < bucket->buflen) { + if (data->status == PHP_BZ2_UNITIALIZED) { + status = BZ2_bzDecompressInit(streamp, 0, data->small_footprint); + + if (BZ_OK != status) { + return PSFS_ERR_FATAL; + } + + data->status = PHP_BZ2_RUNNING; + } + + if (data->status != PHP_BZ2_RUNNING) { + consumed += bucket->buflen; + break; + } + desired = bucket->buflen - bin; if (desired > data->inbuf_len) { desired = data->inbuf_len; @@ -97,7 +123,15 @@ 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)); + if (data->expect_concatenated) { + data->status = PHP_BZ2_UNITIALIZED; + } else { + data->status = PHP_BZ2_FINISHED; + } + } else if (status != BZ_OK) { /* Something bad happened */ php_stream_bucket_delref(bucket TSRMLS_CC); return PSFS_ERR_FATAL; @@ -122,10 +156,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->status == PHP_BZ2_RUNNING) && (flags & PSFS_FLAG_FLUSH_CLOSE)) { /* Spit it out! */ status = BZ_OK; while (status == BZ_OK) { @@ -155,7 +190,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->status == PHP_BZ2_RUNNING) { + BZ2_bzDecompressEnd(&(data->strm)); + } pefree(data->inbuf, data->persistent); pefree(data->outbuf, data->persistent); pefree(data, data->persistent); @@ -291,7 +328,7 @@ static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *fi { php_stream_filter_ops *fops = NULL; php_bz2_filter_data *data; - int status; + int status = BZ_OK; /* Create this filter */ data = pecalloc(1, sizeof(php_bz2_filter_data), persistent); @@ -323,12 +360,22 @@ static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *fi } if (strcasecmp(filtername, "bzip2.decompress") == 0) { - int smallFootprint = 0; + data->small_footprint = 0; + data->expect_concatenated = 0; if (filterparams) { zval **tmpzval = NULL; if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) { + + if (SUCCESS == zend_hash_find(HASH_OF(filterparams), "concatenated", sizeof("concatenated"), (void **) &tmpzval) ) { + SEPARATE_ZVAL(tmpzval); + convert_to_boolean_ex(tmpzval); + data->expect_concatenated = Z_LVAL_PP(tmpzval); + zval_ptr_dtor(tmpzval); + tmpzval = NULL; + } + zend_hash_find(HASH_OF(filterparams), "small", sizeof("small"), (void **) &tmpzval); } else { tmpzval = &filterparams; @@ -337,12 +384,12 @@ static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *fi if (tmpzval) { SEPARATE_ZVAL(tmpzval); convert_to_boolean_ex(tmpzval); - smallFootprint = Z_LVAL_PP(tmpzval); + data->small_footprint = Z_LVAL_PP(tmpzval); zval_ptr_dtor(tmpzval); } } - status = BZ2_bzDecompressInit(&(data->strm), 0, smallFootprint); + data->status = PHP_BZ2_UNITIALIZED; 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 a0818efdae..bdd1efa87a 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; /* }}} */ @@ -88,6 +89,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; @@ -96,7 +103,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; @@ -125,7 +135,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) { @@ -153,7 +163,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); @@ -347,6 +359,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) {