]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: Fixed istream-chain when it has multiple "previous streams".
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 21 Sep 2016 10:26:30 +0000 (13:26 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 21 Sep 2016 12:16:40 +0000 (15:16 +0300)
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.

src/lib/istream-chain.c
src/lib/test-istream-chain.c

index 6880f8d00e2154521b429d364059ae223ae5a32b..026c1dd5845ca72d77c48c0816532b962381aa3d 100644 (file)
@@ -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;
index 7ce37e564982f78a0bbd29580a7e29b37eecbbf6..c9f597050dfd7396ecffc956a139d4786fb51405 100644 (file)
@@ -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();
 }