diff options
author | Ilya Leoshkevich iii@linux.ibm.com <iii@linux.ibm.com> | 2021-03-15 20:15:47 +0100 |
---|---|---|
committer | Hans Kristian Rosbach <hk-github@circlestorm.org> | 2021-03-16 12:21:30 +0100 |
commit | 04ae6d8b19ad32adf66138fb84c62fc7bf310334 (patch) | |
tree | fe46bf2f2abfded4741d26eb8b83b02b8338c1eb | |
parent | 052b9fcb1b4df1321c6fbe5fccc895beeda3c903 (diff) |
Fix bi_valid handling in deflate_quick()
The attached test started failing after commit ad89d5131b29 ("Don't
write end of last block when returning finish_started."): either with
"bi_buf not flushed" message in debug builds, or by producing corrupted
output in release builds.
The problem is that we must not return finish_started when bi_buf is
not empty, because the bits there will be lost. Fix by checking that
bi_valid is not 0.
-rw-r--r-- | CMakeLists.txt | 6 | ||||
-rw-r--r-- | deflate_quick.c | 2 | ||||
-rw-r--r-- | test/deflate_quick_bi_valid.c | 85 |
3 files changed, 92 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ebe858..978b471 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1271,6 +1271,12 @@ if(ZLIB_ENABLE_TESTS) "-DTARGET=${MINIGZIP_COMMAND}" -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/test/GH-751/test.txt -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/test-compress.cmake) + + add_executable(deflate_quick_bi_valid test/deflate_quick_bi_valid.c) + configure_test_executable(deflate_quick_bi_valid) + target_link_libraries(deflate_quick_bi_valid zlib) + set(DEFLATE_QUICK_BI_VALID_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:deflate_quick_bi_valid>) + add_test(NAME deflate_quick_bi_valid COMMAND ${DEFLATE_QUICK_BI_VALID_COMMAND}) endif() FEATURE_SUMMARY(WHAT ALL INCLUDE_QUIET_PACKAGES) diff --git a/deflate_quick.c b/deflate_quick.c index 268cce8..d749b3a 100644 --- a/deflate_quick.c +++ b/deflate_quick.c @@ -65,7 +65,7 @@ Z_INTERNAL block_state deflate_quick(deflate_state *s, int flush) { if (UNLIKELY(s->pending + ((BIT_BUF_SIZE + 7) >> 3) >= s->pending_buf_size)) { flush_pending(s->strm); if (s->strm->avail_out == 0) { - return (last && s->strm->avail_in == 0) ? finish_started : need_more; + return (last && s->strm->avail_in == 0 && s->bi_valid == 0) ? finish_started : need_more; } } diff --git a/test/deflate_quick_bi_valid.c b/test/deflate_quick_bi_valid.c new file mode 100644 index 0000000..d27e0b1 --- /dev/null +++ b/test/deflate_quick_bi_valid.c @@ -0,0 +1,85 @@ +/* Generated by fuzzing - test bi_valid handling in deflate_quick(). */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int main() { + PREFIX3(stream) strm; + memset(&strm, 0, sizeof(strm)); + + int ret = PREFIX(deflateInit2)(&strm, 1, Z_DEFLATED, 31, 1, Z_FILTERED); + if (ret != Z_OK) { + fprintf(stderr, "deflateInit2() failed with code %d\n", ret); + return EXIT_FAILURE; + } + + z_const unsigned char next_in[554] = + "\x8d\xff\xff\xff\xa2\x00\x00\xff\x00\x15\x1b\x1b\xa2\xa2\xaf\xa2" + "\xa2\x00\x00\x00\x02\x00\x1b\x3f\x00\x00\x01\x00\x00\x00\x00\x0b" + "\x00\xab\x00\x00\x00\x00\x01\x00\x01\x2b\x01\x00\x00\x00\x00\x00" + "\x00\x01\x1e\x00\x00\x01\x40\x00\x00\x00\x07\x01\x18\x00\x22\x00" + "\x00\x00\xfd\x39\xff\x00\x00\x00\x1b\xfd\x3b\x00\x68\x00\x00\x01" + "\xff\xff\xff\x57\xf8\x1e\x00\x00\xf2\xf2\xf2\xf2\xfa\xff\xff\xff" + "\xff\x7e\x00\x00\x4a\x00\xc5\x00\x41\x00\x00\x00\x01\x01\x00\x00" + "\x00\x02\x01\x01\x00\xa2\x08\x00\x00\x00\x00\x27\x4a\x4a\x4a\x32" + "\x00\xf9\xff\x00\x02\x9a\xff\x00\x00\x3f\x50\x00\x03\x00\x00\x00" + "\x3d\x00\x08\x2f\x20\x00\x23\x00\x00\x00\x00\x23\x00\xff\xff\xff" + "\xff\xff\xff\xff\x7a\x7a\x9e\xff\xff\x00\x1b\x1b\x04\x00\x1b\x1b" + "\x1b\x1b\x00\x00\x00\xaf\xad\xaf\x00\x00\xa8\x00\x00\x00\x2e\xff" + "\xff\x2e\xc1\x00\x10\x00\x00\x00\x06\x70\x00\x00\x00\xda\x67\x01" + "\x47\x00\x00\x00\x0c\x02\x00\x00\x00\x00\x00\xff\x00\x01\x00\x3f" + "\x54\x00\x00\x00\x1b\x00\x00\x00\x5c\x00\x00\x34\x3e\xc5\x00\x00" + "\x00\x00\x00\x04\x00\x00\x7a\x00\x00\x00\x0a\x01\x00\x00\x00\x00" + "\x00\x00\x7a\x7a\x7a\x7a\x7a\x00\x00\x00\x40\x1b\x1b\x88\x1b\x1b" + "\x1b\x1b\x1b\x1b\x1b\x1f\x1b\x00\x00\x00\x00\x00\x0b\x00\x00\x00" + "\x00\x04\x00\x00\x50\x3e\x7a\x7a\x00\x00\x40\x00\x40\x00\x00\x00" + "\x00\x00\x00\x08\x87\x00\x00\xff\xff\xff\x00\x00\x00\x00\x00\x00" + "\x01\x00\xff\x3d\x00\x11\x4d\x00\x00\x01\xd4\xd4\xd4\xd4\x2d\xd4" + "\xd4\xff\xff\xff\xfa\x01\xd4\x00\xd4\x00\x00\xd4\xd4\xd4\xd4\xd4" + "\xd4\x1e\x1e\x1e\x1e\x00\x00\xfe\xf9\x1e\x1e\x1e\x1e\x1e\x1e\x00" + "\x16\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\x00\x00\x80\x20\x00\x00" + "\xff\x2b\x2b\x2b\x2b\x35\xd4\xd4\x47\x3f\xd4\xd4\xd6\xd4\xd4\x00" + "\x00\x00\x00\x00\x32\x4a\x4a\x4a\x4a\x71\x00\x1b\x1b\x1b\x1b\x1b" + "\x1f\x1b\x1b\x1b\x57\x57\x57\x57\x00\x00\x1b\x08\x2b\x16\xc3\x00" + "\x00\x00\x29\x30\x03\xff\x03\x03\x03\x03\x07\x00\x00\x01\x0b\xff" + "\xff\xf5\xf5\xf5\x00\x00\xfe\xfa\x0f\x0f\x08\x00\xff\x00\x53\x3f" + "\x00\x04\x5d\xa8\x2e\xff\xff\x00\x2f\x2f\x05\xff\xff\xff\x2f\x2f" + "\x2f\x0a\x0a\x0a\x0a\x30\xff\xff\xff\xf0\x0a\x0a\x0a\x00\xff\x3f" + "\x4f\x00\x00\x00\x00\x08\x00\x00\x71\x00\x2e\x00\x00\x00\x00\x00" + "\x71\x71\x00\x71\x71\x71\xf5\x00\x00\x00\x00\x00\x00\x00\xf8\xff" + "\xff\xff\x00\x00\x00\x00\x00\xdb\x3f\x00\xfa\x71\x71\x71\x00\x00" + "\x00\x01\x00\x00\x00\x71\x71\x71\x71\x71"; + strm.next_in = next_in; + unsigned char next_out[1236]; + strm.next_out = next_out; + + strm.avail_in = 554; + strm.avail_out = 31; + ret = PREFIX(deflate)(&strm, Z_FINISH); + if (ret != Z_OK) { + fprintf(stderr, "deflate() failed with code %d\n", ret); + return EXIT_FAILURE; + } + + strm.avail_in = 0; + strm.avail_out = 498; + ret = PREFIX(deflate)(&strm, Z_FINISH); + if (ret != Z_STREAM_END) { + fprintf(stderr, "deflate() failed with code %d\n", ret); + return EXIT_FAILURE; + } + + ret = PREFIX(deflateEnd)(&strm); + if (ret != Z_OK) { + fprintf(stderr, "deflateEnd() failed with code %d\n", ret); + return EXIT_FAILURE; + } +} |