From: Aki Tuomi Date: Wed, 26 Feb 2020 10:57:06 +0000 (+0200) Subject: lib-compression: istream-lz4 - Refactor how chunk header is read X-Git-Tag: 2.3.11.2~566 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e7f738c5324b422e6fe0eaea51b20bb7cb622535;p=thirdparty%2Fdovecot%2Fcore.git lib-compression: istream-lz4 - Refactor how chunk header is read Chunk headers can sometime be at read borders. In this case more data needs to be read. Fixes Panic: file istream.c: line 333 (i_stream_read_memarea): assertion failed: (!stream->blocking) --- diff --git a/src/lib-compression/istream-lz4.c b/src/lib-compression/istream-lz4.c index b7100ec6e6..53f7947679 100644 --- a/src/lib-compression/istream-lz4.c +++ b/src/lib-compression/istream-lz4.c @@ -85,6 +85,46 @@ static int i_stream_lz4_read_header(struct lz4_istream *zstream) return 1; } +static int i_stream_lz4_read_chunk_header(struct lz4_istream *zstream) +{ + int ret; + size_t size; + const unsigned char *data; + struct istream_private *stream = &zstream->istream; + + i_assert(zstream->chunk_buf->used <= IOSTREAM_LZ4_CHUNK_PREFIX_LEN); + ret = i_stream_read_more(stream->parent, &data, &size); + size = I_MIN(size, IOSTREAM_LZ4_CHUNK_PREFIX_LEN - zstream->chunk_buf->used); + buffer_append(zstream->chunk_buf, data, size); + i_stream_skip(stream->parent, size); + if (ret < 0) { + stream->istream.stream_errno = stream->parent->stream_errno; + if (stream->istream.stream_errno == 0) { + stream->istream.eof = TRUE; + stream->cached_stream_size = + stream->istream.v_offset + + stream->pos - stream->skip; + } + return ret; + } + i_assert(ret != 0 || !stream->istream.blocking); + if (ret == 0) + return ret; + if (zstream->chunk_buf->used < IOSTREAM_LZ4_CHUNK_PREFIX_LEN) + return 0; + zstream->chunk_size = zstream->chunk_left = + be32_to_cpu_unaligned(zstream->chunk_buf->data); + if (zstream->chunk_size == 0 || + zstream->chunk_size > ISTREAM_LZ4_CHUNK_SIZE) { + lz4_read_error(zstream, t_strdup_printf( + "invalid lz4 chunk size: %u", zstream->chunk_size)); + stream->istream.stream_errno = EINVAL; + return -1; + } + buffer_set_used_size(zstream->chunk_buf, 0); + return 1; +} + static ssize_t i_stream_lz4_read(struct istream_private *stream) { struct lz4_istream *zstream = (struct lz4_istream *)stream; @@ -105,38 +145,12 @@ static ssize_t i_stream_lz4_read(struct istream_private *stream) } if (zstream->chunk_left == 0) { - i_assert(zstream->chunk_buf->used <= IOSTREAM_LZ4_CHUNK_PREFIX_LEN); - ret = i_stream_read_more(stream->parent, &data, &size); - if (size > IOSTREAM_LZ4_CHUNK_PREFIX_LEN - zstream->chunk_buf->used) - size = IOSTREAM_LZ4_CHUNK_PREFIX_LEN - zstream->chunk_buf->used; - buffer_append(zstream->chunk_buf, data, size); - i_stream_skip(stream->parent, size); - if (ret < 0) { - stream->istream.stream_errno = - stream->parent->stream_errno; - if (stream->istream.stream_errno == 0) { - stream->istream.eof = TRUE; - stream->cached_stream_size = - stream->istream.v_offset + - stream->pos - stream->skip; - } - return ret; + while ((ret = i_stream_lz4_read_chunk_header(zstream)) == 0) { + if (ret == 0 && !stream->istream.blocking) + return 0; } - if (ret == 0 && !stream->istream.eof) - return 0; - if (zstream->chunk_buf->used < IOSTREAM_LZ4_CHUNK_PREFIX_LEN) - return 0; - zstream->chunk_size = zstream->chunk_left = - be32_to_cpu_unaligned(zstream->chunk_buf->data); - buffer_set_used_size(zstream->chunk_buf, 0); - if (zstream->chunk_size == 0 || - zstream->chunk_size > ISTREAM_LZ4_CHUNK_SIZE) { - lz4_read_error(zstream, t_strdup_printf( - "invalid lz4 chunk size: %u", zstream->chunk_size)); - stream->istream.stream_errno = EINVAL; - return -1; - } - buffer_set_used_size(zstream->chunk_buf, 0); + if (ret < 0) + return ret; } /* read the whole compressed chunk into memory */ @@ -156,6 +170,7 @@ static ssize_t i_stream_lz4_read(struct istream_private *stream) } zstream->istream.istream.stream_errno = zstream->istream.parent->stream_errno; + i_assert(ret != 0 || !stream->istream.blocking); return ret; } /* if we already have max_buffer_size amount of data, fail here */