From: Timo Sirainen Date: Wed, 21 Sep 2016 10:26:30 +0000 (+0300) Subject: lib: Fixed istream-chain when it has multiple "previous streams". X-Git-Tag: 2.2.26~239 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=946de454a6e2594717bdc4450164dd0db1e96b60;p=thirdparty%2Fdovecot%2Fcore.git lib: Fixed istream-chain when it has multiple "previous streams". Fixes assert: Panic: file istream-chain.c: line 223 (i_stream_chain_read): assertion failed: (cur_data_pos == data_size) Unit test for it by Stephan Bosch. --- diff --git a/src/lib/istream-chain.c b/src/lib/istream-chain.c index 6880f8d00e..026c1dd584 100644 --- a/src/lib/istream-chain.c +++ b/src/lib/istream-chain.c @@ -23,7 +23,11 @@ struct istream_chain { struct chain_istream { struct istream_private istream; - size_t prev_stream_left, prev_skip; + /* how much of the previous link's stream still exists at the + beginning of our buffer. skipping through this should point to + the beginning of the current link's stream. */ + size_t prev_stream_left; + size_t prev_skip; bool have_explicit_max_buffer_size; struct istream_chain chain; @@ -131,12 +135,16 @@ static void i_stream_chain_read_next(struct chain_istream *cstream) if (cstream->prev_stream_left > 0) { /* we've already buffered some of the prev_input. continue - appending the rest to it. */ + appending the rest to it. if it's already at EOF, there's + nothing more to append. */ cur_data_pos = cstream->istream.pos - (cstream->istream.skip + cstream->prev_stream_left); i_assert(cur_data_pos <= data_size); data += cur_data_pos; data_size -= cur_data_pos; + /* the stream has now become "previous", so its contents in + buffer are now part of prev_stream_left. */ + cstream->prev_stream_left += cur_data_pos; } else { cstream->istream.pos = 0; cstream->istream.skip = 0; diff --git a/src/lib/test-istream-chain.c b/src/lib/test-istream-chain.c index 7ce37e5649..c9f597050d 100644 --- a/src/lib/test-istream-chain.c +++ b/src/lib/test-istream-chain.c @@ -80,8 +80,106 @@ static void test_istream_chain_early_end(void) test_end(); } +static void test_istream_chain_accumulate(void) +{ + struct istream *input; + struct istream *test_input, *test_input2, *test_input3, *test_input4, + *test_input5; + struct istream_chain *chain; + const unsigned char *data; + size_t size; + + test_begin("istream chain"); + + test_input = test_istream_create("aaaaaaaaaaaaaaaaaaaa"); + test_input2 = test_istream_create("bbbbbbbbbbbbbbbbbbbbbbbbb"); + test_input3 = test_istream_create("cccccccccccccccccccccccccccccc"); + test_input4 = test_istream_create("ddddddddddddddddddddddddd"); + test_input5 = test_istream_create("eeeeeeeeeeeeeeeeeeee"); + + input = i_stream_create_chain(&chain); + /* no input */ + test_assert(i_stream_read(input) == 0); + + /* first stream */ + i_stream_chain_append(chain, test_input); + test_assert(i_stream_read_data(input, &data, &size, 0) == 1); + test_assert(size == 20); + test_assert(memcmp(data, "aaaaaaaaaaaaaaaaaaaa", 20) == 0); + + /* partially skip */ + i_stream_skip(input, 12); + + /* second stream */ + i_stream_chain_append(chain, test_input2); + test_assert(i_stream_read_data(input, &data, &size, 10) == 1); + test_assert(size == 33); + test_assert(memcmp(data, "aaaaaaaa" + "bbbbbbbbbbbbbbbbbbbbbbbbb", 33) == 0); + + /* partially skip */ + i_stream_skip(input, 12); + + /* third stream */ + i_stream_chain_append(chain, test_input3); + test_assert(i_stream_read_data(input, &data, &size, 25) == 1); + test_assert(size == 51); + test_assert(memcmp(data, "bbbbbbbbbbbbbbbbbbbbb" + "cccccccccccccccccccccccccccccc", 51) == 0); + + /* partially skip */ + i_stream_skip(input, 12); + + /* forth stream */ + i_stream_chain_append(chain, test_input4); + test_assert(i_stream_read_data(input, &data, &size, 40) == 1); + test_assert(size == 64); + test_assert(memcmp(data, "bbbbbbbbb" + "cccccccccccccccccccccccccccccc" + "ddddddddddddddddddddddddd", 64) == 0); + + /* partially skip */ + i_stream_skip(input, 6); + + /* fifth stream */ + i_stream_chain_append(chain, test_input5); + test_assert(i_stream_read_data(input, &data, &size, 60) == 1); + test_assert(size == 78); + test_assert(memcmp(data, "bbb" + "cccccccccccccccccccccccccccccc" + "ddddddddddddddddddddddddd" + "eeeeeeeeeeeeeeeeeeee", 78) == 0); + + /* EOF */ + i_stream_chain_append_eof(chain); + test_assert(i_stream_read(input) == -1); + test_assert(input->eof && input->stream_errno == 0); + test_assert(i_stream_read_data(input, &data, &size, 78) == -1); + test_assert(size == 78); + test_assert(memcmp(data, "bbb" + "cccccccccccccccccccccccccccccc" + "ddddddddddddddddddddddddd" + "eeeeeeeeeeeeeeeeeeee", 78) == 0); + + /* skip rest */ + i_stream_skip(input, 78); + + test_assert(i_stream_read(input) == -1); + test_assert(input->eof && input->stream_errno == 0); + data = i_stream_get_data(input, &size); + test_assert(size == 0); + + i_stream_unref(&input); + + i_stream_unref(&test_input); + i_stream_unref(&test_input2); + i_stream_unref(&test_input3); + test_end(); +} + void test_istream_chain(void) { test_istream_chain_basic(); test_istream_chain_early_end(); + test_istream_chain_accumulate(); }