=== modified file 'unittest/backup/Makefile.am' --- unittest/backup/Makefile.am 2009-07-01 06:53:15 +0000 +++ unittest/backup/Makefile.am 2009-07-10 12:56:59 +0000 @@ -5,6 +5,7 @@ LDADD= libstreamtest.la STREAMTESTS = bstr_callback_errors-t bstr_io_errors-t bstr_eos-t STREAMTESTS += bstr_data_chunks-t bstr_random_chunks-t STREAMTESTS += bstr_extra-t bstr_extra1-t +STREAMTESTS += bug45737-t noinst_PROGRAMS = $(STREAMTESTS) @@ -15,6 +16,7 @@ bstr_io_errors_t_SOURCES = bstr_io bstr_eos_t_SOURCES = bstr_eos-t.c catalog.c bstr_extra_t_SOURCES = bstr_extra-t.c catalog.c bstr_extra1_t_SOURCES = bstr_extra1-t.c catalog.c +bug45737_t_SOURCES = bug45737-t.c no_catalog.c noinst_HEADERS = stream_test.h catalog.h === added file 'unittest/backup/bug45737-t.c' --- unittest/backup/bug45737-t.c 1970-01-01 00:00:00 +0000 +++ unittest/backup/bug45737-t.c 2009-07-10 12:54:50 +0000 @@ -0,0 +1,111 @@ +/* @file + + Provoke assertion failure detected in BUG#44569. This is the assertion in + bstream_write_part() at line 1087 (stream_v1_transport.c). + @code + /x + If a complete output block is filled, we flush the stream. Output buffer + becomes empty and ready to accept new data. + x/ + if (s->buf.pos == s->buf.end) + { + ret= bstream_flush(s); + if (ret != BSTREAM_OK) + return BSTREAM_ERROR; + } + + ASSERT(s->buf.pos < s->buf.end); + @endcode + + The code assumes that after bstream_flush() there is some free space in the + output buffer (buf.pos < buf.end). But this is not the case if it happens that + the buffer is empty and we are at the end of output block (buf.begin == + buf.pos == buf.end). In that case bstream_flush() does nothing leving the + output buffer without any free space in it. + + The code below drives bstream library into that situation. +*/ + +#include + +#include "stream_test.h" + +/* import some low-level functions from bstream library */ + +int bstream_write_blob(backup_stream*, blob); +int bstream_write_part(backup_stream*, blob*, blob); +int bstream_flush(backup_stream*); + + +void run_test() +{ + test_backup_stream stream; + backup_stream *bstr= (backup_stream*)&stream; + byte buf[1089]; /* The size here is crucial - see below */ + blob data; + int i; + size_t remains; + int ret= BSTREAM_OK; + + stream_block_size= sizeof(buf); + + /* setup data blob */ + memset(buf, 0x01, sizeof(buf)); + data.begin= buf; + data.end= buf + sizeof(buf); + + + ret= backup_stream_open_wr(&stream, "extra1.bst"); + if (ret) + { + diag("Failed to open stream for writing"); + return; + } + + /* + In the following loop we try to arrive at a situation where output stream + is at a beginning of next output block. If we are not there yet, we write + enough data to fill a complete block so that we move to next one (we must + leave 2 bytes for fragment headers - wiht block size > 64 the data will be + split into at least 2 fragments). + + This must be repeated because first couple of blocks contains additional + data (block size and init block count). + */ + + for(i=0; i<10; ++i) + { + remains= bstr->buf.end - bstr->buf.pos; + data.end = buf + remains - 2; // leave 2 bytes for fragment headers + ret= bstream_write_blob(bstr, data); + bstream_flush(bstr); + + if (bstr->buf.end == bstr->buf.pos + bstr->block_size) + break; + } + + + /* + It is important that we write 1088 bytes. This is an amount which is + bigger than MIN_WRITE_SIZE (1024) and which can be saved in a single + big fragment (whose least 6 bits are 0). Also, stream block size must + be equal this amount + 1 byte for fragment header. + + Only under these conditions we arrive at the situation where output + buffer is empty and at the end of the current output block. + */ + + data.end= buf + 1088; + bstream_write_blob(bstr, data); + + /* + Now we should have: + bstr->buf.begin == bstr->buf.header == bstr->buf.pos == bstr->buf.end + which leads to assertion failure. We try to write again to trigger it. + */ + + data.end= buf + 60; + bstream_write_part(bstr, &data, data); + + backup_stream_close(&stream); +}