diff options
author | Jack Lloyd <[email protected]> | 2017-11-25 12:50:17 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-11-25 12:50:17 -0500 |
commit | 121f8bee6c2c6891bfb855d39aad66703e0ae35e (patch) | |
tree | f8dc1f6cfff1e0b3a66c0048bbac9e2943410a4a | |
parent | 3f8c4add59f4db347f8594a49c846c85ce1e296d (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.cpp | 10 | ||||
-rw-r--r-- | src/tests/test_compression.cpp | 55 | ||||
-rw-r--r-- | src/tests/test_filters.cpp | 7 |
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"); |