aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-11-25 12:50:17 -0500
committerJack Lloyd <[email protected]>2017-11-25 12:50:17 -0500
commit121f8bee6c2c6891bfb855d39aad66703e0ae35e (patch)
treef8dc1f6cfff1e0b3a66c0048bbac9e2943410a4a
parent3f8c4add59f4db347f8594a49c846c85ce1e296d (diff)
Fix bzip2 compression issue.
When finishing, bzip2 returns BZ_STREAM_END when it has produced all output. If we end up calling the compression routine again (even with avail_in == 0), bzip2 returns an error.
-rw-r--r--src/lib/compression/compress_utils.cpp10
-rw-r--r--src/tests/test_compression.cpp55
-rw-r--r--src/tests/test_filters.cpp7
3 files changed, 48 insertions, 24 deletions
diff --git a/src/lib/compression/compress_utils.cpp b/src/lib/compression/compress_utils.cpp
index f4b41fd5b..6bdf3d0fd 100644
--- a/src/lib/compression/compress_utils.cpp
+++ b/src/lib/compression/compress_utils.cpp
@@ -84,9 +84,15 @@ void Stream_Compression::process(secure_vector<uint8_t>& buf, size_t offset, uin
while(true)
{
- m_stream->run(flags);
+ const bool stream_end = m_stream->run(flags);
- if(m_stream->avail_out() == 0)
+ if(stream_end)
+ {
+ BOTAN_ASSERT(m_stream->avail_in() == 0, "After stream is done, no input remains to be processed");
+ m_buffer.resize(m_buffer.size() - m_stream->avail_out());
+ break;
+ }
+ else if(m_stream->avail_out() == 0)
{
const size_t added = 8 + m_buffer.size();
m_buffer.resize(m_buffer.size() + added);
diff --git a/src/tests/test_compression.cpp b/src/tests/test_compression.cpp
index 04eb26200..c85dd5a5d 100644
--- a/src/tests/test_compression.cpp
+++ b/src/tests/test_compression.cpp
@@ -80,6 +80,7 @@ class Compression_Tests final : public Test
const Botan::secure_vector<uint8_t> empty;
const Botan::secure_vector<uint8_t> all_zeros(text_len, 0);
const Botan::secure_vector<uint8_t> random_binary = Test::rng().random_vec(text_len);
+ const Botan::secure_vector<uint8_t> short_text = { 'f', 'o', 'o', '\n' };
const uint8_t* textb = reinterpret_cast<const uint8_t*>(text_str);
const Botan::secure_vector<uint8_t> text(textb, textb + text_len);
@@ -92,6 +93,8 @@ class Compression_Tests final : public Test
const size_t c9_r = run_compression(result, 9, *c, *d, random_binary);
const size_t c1_t = run_compression(result, 1, *c, *d, text);
const size_t c9_t = run_compression(result, 9, *c, *d, text);
+ const size_t c1_s = run_compression(result, 1, *c, *d, short_text);
+ const size_t c9_s = run_compression(result, 9, *c, *d, short_text);
result.test_gte("Empty input L1 compresses to non-empty output", c1_e, 1);
result.test_gte("Empty input L9 compresses to non-empty output", c9_e, 1);
@@ -100,6 +103,7 @@ class Compression_Tests final : public Test
result.test_gte("Level 9 compresses zeros at least as well as level 1", c1_z, c9_z);
result.test_gte("Level 9 compresses random at least as well as level 1", c1_r, c9_r);
result.test_gte("Level 9 compresses text at least as well as level 1", c1_t, c9_t);
+ result.test_gte("Level 9 compresses short text at least as well as level 1", c1_s, c9_s);
result.test_lt("Zeros compresses much better than text", c1_z / 8, c1_t);
result.test_lt("Text compresses much better than random", c1_t / 2, c1_r);
@@ -124,31 +128,46 @@ class Compression_Tests final : public Test
Botan::Decompression_Algorithm& d,
const Botan::secure_vector<uint8_t>& msg)
{
- Botan::secure_vector<uint8_t> compressed = msg;
- Botan::secure_vector<uint8_t> flush_bits;
- Botan::secure_vector<uint8_t> final_bits;
+ Botan::secure_vector<uint8_t> compressed(2*msg.size());
- c.start(level);
- c.update(compressed);
- c.update(flush_bits, 0, true);
- c.finish(final_bits);
+ for(bool with_flush : { true, false })
+ {
+ try
+ {
+ compressed = msg;
- compressed += flush_bits;
- compressed += final_bits;
+ c.start(level);
+ c.update(compressed, 0, false);
+
+ if(with_flush)
+ {
+ Botan::secure_vector<uint8_t> flush_bits;
+ c.update(flush_bits, 0, true);
+ compressed += flush_bits;
+ }
- const size_t c_size = compressed.size();
+ Botan::secure_vector<uint8_t> final_bits;
+ c.finish(final_bits);
+ compressed += final_bits;
- Botan::secure_vector<uint8_t> decompressed = compressed;
- d.start();
- d.update(decompressed);
+ Botan::secure_vector<uint8_t> decompressed = compressed;
+ d.start();
+ d.update(decompressed);
- Botan::secure_vector<uint8_t> final_outputs;
- d.finish(final_outputs);
+ Botan::secure_vector<uint8_t> final_outputs;
+ d.finish(final_outputs);
- decompressed += final_outputs;
+ decompressed += final_outputs;
+
+ result.test_eq("compression round tripped", msg, decompressed);
+ }
+ catch(Botan::Exception& e)
+ {
+ result.test_failure(e.what());
+ }
+ }
- result.test_eq("compression round tripped", msg, decompressed);
- return c_size;
+ return compressed.size();
}
};
diff --git a/src/tests/test_filters.cpp b/src/tests/test_filters.cpp
index 84e74e12d..8133e4bc9 100644
--- a/src/tests/test_filters.cpp
+++ b/src/tests/test_filters.cpp
@@ -463,7 +463,7 @@ class Filter_Tests final : public Test
Test::Result test_pipe_compress()
{
- Test::Result result("Pipe");
+ Test::Result result("Pipe compress zlib");
#if defined(BOTAN_HAS_ZLIB)
@@ -498,7 +498,7 @@ class Filter_Tests final : public Test
Test::Result test_pipe_compress_bzip2()
{
- Test::Result result("Pipe");
+ Test::Result result("Pipe compress bzip2");
#if defined(BOTAN_HAS_BZIP2)
@@ -514,8 +514,7 @@ class Filter_Tests final : public Test
pipe.end_msg();
auto compr = pipe.read_all(0);
- // Can't do equality check on compression because output may differ
- result.test_lt("Compressed is shorter", compr.size(), input_str.size());
+ // Here the output is actually longer than the input as input is so short
std::unique_ptr<Botan::Decompression_Filter> decomp_f(new Botan::Decompression_Filter("bzip2"));
result.test_eq("Decompressor name", decomp_f->name(), "Bzip2_Decompression");